home *** CD-ROM | disk | FTP | other *** search
/ Netscape Plug-Ins Developer's Kit / Netscape_Plug-Ins_Developers_Kit.iso / CGIPERL / MACPERL / MSRCE418.HQX / Perl Source ƒ / Perl / toke.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-01-15  |  62.0 KB  |  2,825 lines

  1. /* $RCSfile: toke.c,v $$Revision: 4.0.1.9 $$Date: 1993/02/05 19:48:43 $
  2.  *
  3.  *    Copyright (c) 1991, Larry Wall
  4.  *
  5.  *    You may distribute under the terms of the Perl Artistic License,
  6.  *    as specified in the README file.
  7.  *
  8.  * $Log:    toke.c,v $
  9.  * Revision 4.0.1.9  1993/02/05  19:48:43  lwall
  10.  * patch36: now detects ambiguous use of filetest operators as well as unary
  11.  * patch36: fixed ambiguity on - within tr///
  12.  * 
  13.  * Revision 4.0.1.8  1992/06/23  12:33:45  lwall
  14.  * patch35: bad interaction between backslash and hyphen in tr///
  15.  * 
  16.  * Revision 4.0.1.7  92/06/11  21:16:30  lwall
  17.  * patch34: expectterm incorrectly set to indicate start of program or block
  18.  * 
  19.  * Revision 4.0.1.6  92/06/08  16:03:49  lwall
  20.  * patch20: an EXPR may now start with a bareword
  21.  * patch20: print $fh EXPR can now expect term rather than operator in EXPR
  22.  * patch20: added ... as variant on ..
  23.  * patch20: new warning on spurious backslash
  24.  * patch20: new warning on missing $ for foreach variable
  25.  * patch20: "foo"x1024 now legal without space after x
  26.  * patch20: new warning on print accidentally used as function
  27.  * patch20: tr/stuff// wasn't working right
  28.  * patch20: 2. now eats the dot
  29.  * patch20: <@ARGV> now notices @ARGV
  30.  * patch20: tr/// now lets you say \-
  31.  * 
  32.  * Revision 4.0.1.5  91/11/11  16:45:51  lwall
  33.  * patch19: default arg for shift was wrong after first subroutine definition
  34.  * 
  35.  * Revision 4.0.1.4  91/11/05  19:02:48  lwall
  36.  * patch11: \x and \c were subject to double interpretation in regexps
  37.  * patch11: prepared for ctype implementations that don't define isascii()
  38.  * patch11: nested list operators could miscount parens
  39.  * patch11: once-thru blocks didn't display right in the debugger
  40.  * patch11: sort eval "whatever" didn't work
  41.  * patch11: underscore is now allowed within literal octal and hex numbers
  42.  * 
  43.  * Revision 4.0.1.3  91/06/10  01:32:26  lwall
  44.  * patch10: m'$foo' now treats string as single quoted
  45.  * patch10: certain pattern optimizations were botched
  46.  * 
  47.  * Revision 4.0.1.2  91/06/07  12:05:56  lwall
  48.  * patch4: new copyright notice
  49.  * patch4: debugger lost track of lines in eval
  50.  * patch4: //o and s///o now optimize themselves fully at runtime
  51.  * patch4: added global modifier for pattern matches
  52.  * 
  53.  * Revision 4.0.1.1  91/04/12  09:18:18  lwall
  54.  * patch1: perl -de "print" wouldn't stop at the first statement
  55.  * 
  56.  * Revision 4.0  91/03/20  01:42:14  lwall
  57.  * 4.0 baseline.
  58.  * 
  59.  */
  60.  
  61. #include "EXTERN.h"
  62. #include "perl.h"
  63.  
  64. #ifdef I_FCNTL
  65. #include <fcntl.h>
  66. #endif
  67. #ifdef I_SYS_FILE
  68. #include <sys/file.h>
  69. #endif
  70.  
  71. #include "perly.h"
  72.  
  73. static void set_csh();
  74.  
  75. #ifdef f_next
  76. #undef f_next
  77. #endif
  78.  
  79. /* which backslash sequences to keep in m// or s// */
  80.  
  81. static char *patleave = "\\.^$@dDwWsSbB+*?|()-nrtfeaxc0123456789[{]}";
  82.  
  83. char *reparse;        /* if non-null, scanident found ${foo[$bar]} */
  84.  
  85. void checkcomma();
  86.  
  87. #ifdef CLINE
  88. #undef CLINE
  89. #endif
  90. #define CLINE (cmdline = (curcmd->c_line < cmdline ? curcmd->c_line : cmdline))
  91.  
  92. #ifdef atarist
  93. #define PERL_META(c) ((c) | 128)
  94. #else
  95. #define META(c) ((c) | 128)
  96. #endif
  97.  
  98. #define RETURN(retval) return (bufptr = s,(int)retval)
  99. #define OPERATOR(retval) return (expectterm = TRUE,bufptr = s,(int)retval)
  100. #define TERM(retval) return (CLINE, expectterm = FALSE,bufptr = s,(int)retval)
  101. #define LOOPX(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)LOOPEX)
  102. #define FTST(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)FILETEST)
  103. #define FUN0(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC0)
  104. #define FUN1(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC1)
  105. #define FUN2(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC2)
  106. #define FUN2x(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC2x)
  107. #define FUN3(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC3)
  108. #define FUN4(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC4)
  109. #define FUN5(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC5)
  110. #define FL(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FLIST)
  111. #define FL2(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FLIST2)
  112. #define HFUN(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)HSHFUN)
  113. #define HFUN3(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)HSHFUN3)
  114. #define LFUN(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)LVALFUN)
  115. #define AOP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)ADDOP)
  116. #define MOP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)MULOP)
  117. #define EOP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)EQOP)
  118. #define ROP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)RELOP)
  119. #define FOP(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP)
  120. #define FOP2(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP2)
  121. #define FOP3(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP3)
  122. #define FOP4(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP4)
  123. #define FOP22(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP22)
  124. #define FOP25(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP25)
  125.  
  126. #ifdef macintosh
  127. #define CHOOS(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)CHOOSE)
  128. #define MIN1(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FMIN1)
  129. #define FUN12(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FUNC12)
  130. #endif
  131.  
  132. static char *last_uni;
  133.  
  134. /* This bit of chicanery makes a unary function followed by
  135.  * a parenthesis into a function with one argument, highest precedence.
  136.  */
  137. #define UNI(f) return(yylval.ival = f, \
  138.     expectterm = TRUE, \
  139.     bufptr = s, \
  140.     last_uni = oldbufptr, \
  141.     (*s == '(' || (s = skipspace(s), *s == '(') ? (int)FUNC1 : (int)UNIOP) )
  142.  
  143. /* This does similarly for list operators, merely by pretending that the
  144.  * paren came before the listop rather than after.
  145.  */
  146. #ifdef atarist
  147. #define LOP(f) return(CLINE, *s == '(' || (s = skipspace(s), *s == '(') ? \
  148.     (*s = (char) PERL_META('('), bufptr = oldbufptr, '(') : \
  149.     (yylval.ival=f,expectterm = TRUE,bufptr = s,(int)LISTOP))
  150. #else
  151. #define LOP(f) return(CLINE, *s == '(' || (s = skipspace(s), *s == '(') ? \
  152.     (*s = (char) META('('), bufptr = oldbufptr, '(') : \
  153.     (yylval.ival=f,expectterm = TRUE,bufptr = s,(int)LISTOP))
  154. #endif
  155. /* grandfather return to old style */
  156. #define OLDLOP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)LISTOP)
  157.  
  158. char *
  159. skipspace(s)
  160. register char *s;
  161. {
  162.     while (s < bufend && isSPACE(*s))
  163.     s++;
  164.     return s;
  165. }
  166.  
  167. void
  168. check_uni() {
  169.     char *s;
  170.     char ch;
  171.  
  172.     if (oldoldbufptr != last_uni)
  173.     return;
  174.     while (isSPACE(*last_uni))
  175.     last_uni++;
  176.     for (s = last_uni; isALNUM(*s) || *s == '-'; s++) ;
  177.     ch = *s;
  178.     *s = '\0';
  179.     warn("Warning: Use of \"%s\" without parens is ambiguous", last_uni);
  180.     *s = ch;
  181. }
  182.  
  183. #ifdef CRIPPLED_CC
  184.  
  185. #undef UNI
  186. #undef LOP
  187. #define UNI(f) return uni(f,s)
  188. #define LOP(f) return lop(f,s)
  189.  
  190. int
  191. uni(f,s)
  192. int f;
  193. char *s;
  194. {
  195.     yylval.ival = f;
  196.     expectterm = TRUE;
  197.     bufptr = s;
  198.     last_uni = oldbufptr;
  199.     if (*s == '(')
  200.     return FUNC1;
  201.     s = skipspace(s);
  202.     if (*s == '(')
  203.     return FUNC1;
  204.     else
  205.     return UNIOP;
  206. }
  207.  
  208. int
  209. lop(f,s)
  210. int f;
  211. char *s;
  212. {
  213.     CLINE;
  214.     if (*s != '(')
  215.     s = skipspace(s);
  216.     if (*s == '(') {
  217. #ifdef atarist
  218.     *s = PERL_META('(');
  219. #else
  220.     *s = META('(');
  221. #endif
  222.     bufptr = oldbufptr;
  223.     return '(';
  224.     }
  225.     else {
  226.     yylval.ival=f;
  227.     expectterm = TRUE;
  228.     bufptr = s;
  229.     return LISTOP;
  230.     }
  231. }
  232.  
  233. #endif /* CRIPPLED_CC */
  234.  
  235. #ifdef macintosh
  236. static bool in_format = FALSE;
  237. static bool firstline = TRUE;
  238. #endif
  239.  
  240. int
  241. yylex()
  242. {
  243.     register char *s = bufptr;
  244.     register char *d;
  245.     register int tmp;
  246.     extern int yychar;        /* last token */
  247. #ifndef macintosh
  248.     static bool in_format = FALSE;
  249.     static bool firstline = TRUE;
  250. #endif
  251.  
  252.     oldoldbufptr = oldbufptr;
  253.     oldbufptr = s;
  254.  
  255.   retry:
  256. #ifdef YYDEBUG
  257.     if (debug & 1)
  258. #ifdef macintosh
  259.     if (index(s,'\n'))
  260.         fprintf(perldbg,"Tokener at %s",s);
  261.     else
  262.         fprintf(perldbg,"Tokener at %s\n",s);
  263. #else
  264.     if (index(s,'\n'))
  265.         fprintf(stderr,"Tokener at %s",s);
  266.     else
  267.         fprintf(stderr,"Tokener at %s\n",s);
  268. #endif
  269. #endif
  270. #ifdef macintosh
  271.      /* Ignore option-space */
  272.     if ((unsigned char) *s == 0312)
  273.          *s    =    ' ';
  274. #endif
  275. #ifdef BADSWITCH
  276.     if (*s & 128) {
  277.     if ((*s & 127) == '(') {
  278.         *s++ = '(';
  279.         oldbufptr = s;
  280.     }
  281.     else if ((*s & 127) == '}') {
  282.         *s++ = '}';
  283.         RETURN('}');
  284.     }
  285.     else
  286.         warn("Unrecognized character \\%03o ignored", *s++ & 255);
  287.     goto retry;
  288.     }
  289. #endif
  290.     switch (*s) {
  291.     default:
  292.     if ((*s & 127) == '(') {
  293.         *s++ = '(';
  294.         oldbufptr = s;
  295.     }
  296.     else if ((*s & 127) == '}') {
  297.         *s++ = '}';
  298.         RETURN('}');
  299.     }
  300.     else
  301.         warn("Unrecognized character \\%03o ignored", *s++ & 255);
  302.     goto retry;
  303. #ifdef macintosh
  304.     case 1:    /* MPW C preprocessor seems to insert these to mark token boundaries */
  305.         ++s;    /* Ignore them                                  */
  306.     goto retry;
  307. #endif
  308.     case 4:
  309.     case 26:
  310.     goto fake_eof;            /* emulate EOF on ^D or ^Z */
  311.     case 0:
  312.     if (!rsfp)
  313.         RETURN(0);
  314.     if (s++ < bufend)
  315.         goto retry;            /* ignore stray nulls */
  316.     last_uni = 0;
  317.     if (firstline) {
  318.         firstline = FALSE;
  319.         if (minus_n || minus_p || perldb) {
  320.         str_set(linestr,"");
  321.         if (perldb) {
  322. #ifndef macintosh
  323.             char *getenv();
  324. #endif
  325.             char *pdb = getenv("PERLDB");
  326.  
  327.             str_cat(linestr, pdb ? pdb : "require 'perldb.pl'");
  328.             str_cat(linestr, ";");
  329.         }
  330.         if (minus_n || minus_p) {
  331.             str_cat(linestr,"line: while (<>) {");
  332.             if (minus_l)
  333.             str_cat(linestr,"chop;");
  334.             if (minus_a)
  335.             str_cat(linestr,"@F=split(' ');");
  336.         }
  337.         oldoldbufptr = oldbufptr = s = str_get(linestr);
  338.         bufend = linestr->str_ptr + linestr->str_cur;
  339.         goto retry;
  340.         }
  341.     }
  342.     if (in_format) {
  343.         bufptr = bufend;
  344.         yylval.formval = load_format();
  345.         in_format = FALSE;
  346.         oldoldbufptr = oldbufptr = s = str_get(linestr) + 1;
  347.         bufend = linestr->str_ptr + linestr->str_cur;
  348.         OPERATOR(FORMLIST);
  349.     }
  350. #ifdef macintosh
  351.         SpinMacCursor();
  352. #endif
  353.     curcmd->c_line++;
  354. #ifdef CRYPTSCRIPT
  355.     cryptswitch();
  356. #endif /* CRYPTSCRIPT */
  357.     do {
  358.         if ((s = str_gets(linestr, rsfp, 0)) == Nullch) {
  359.           fake_eof:
  360.         if (rsfp) {
  361.             if (preprocess)
  362.             (void)mypclose(rsfp);
  363.             else if ((FILE*)rsfp == stdin)
  364.             clearerr(stdin);
  365.             else
  366.             (void)fclose(rsfp);
  367.             rsfp = Nullfp;
  368.         }
  369.         if (minus_n || minus_p) {
  370.             str_set(linestr,minus_p ? ";}continue{print" : "");
  371.             str_cat(linestr,";}");
  372.             oldoldbufptr = oldbufptr = s = str_get(linestr);
  373.             bufend = linestr->str_ptr + linestr->str_cur;
  374.             minus_n = minus_p = 0;
  375.             goto retry;
  376.         }
  377.         oldoldbufptr = oldbufptr = s = str_get(linestr);
  378.         str_set(linestr,"");
  379.         RETURN(';');    /* not infinite loop because rsfp is NULL now */
  380.         }
  381.         if (doextract && *linestr->str_ptr == '#')
  382.         doextract = FALSE;
  383.     } while (doextract);
  384.     oldoldbufptr = oldbufptr = bufptr = s;
  385.     if (perldb) {
  386.         STR *str = Str_new(85,0);
  387.  
  388.         str_sset(str,linestr);
  389.         astore(stab_xarray(curcmd->c_filestab),(int)curcmd->c_line,str);
  390.     }
  391. #ifdef DEBUG
  392.     if (firstline) {
  393.         char *showinput();
  394.         s = showinput();
  395.     }
  396. #endif
  397.     bufend = linestr->str_ptr + linestr->str_cur;
  398.     if (curcmd->c_line == 1) {
  399. #ifdef macintosh
  400.         curcmd->c_line += extract_offset;
  401. #endif
  402.         if (*s == '#' && s[1] == '!') {
  403.         if (!in_eval && !instr(s,"perl") && instr(origargv[0],"perl")) {
  404.             char **newargv;
  405.             char *cmd;
  406.  
  407.             s += 2;
  408.             if (*s == ' ')
  409.             s++;
  410.             cmd = s;
  411.             while (s < bufend && !isSPACE(*s))
  412.             s++;
  413.             *s++ = '\0';
  414.             while (s < bufend && isSPACE(*s))
  415.             s++;
  416.             if (s < bufend) {
  417.             Newz(899,newargv,origargc+3,char*);
  418.             newargv[1] = s;
  419.             while (s < bufend && !isSPACE(*s))
  420.                 s++;
  421.             *s = '\0';
  422.             Copy(origargv+1, newargv+2, origargc+1, char*);
  423.             }
  424.             else
  425.             newargv = origargv;
  426.             newargv[0] = cmd;
  427.             execv(cmd,newargv);
  428.             fatal("Can't exec %s", cmd);
  429.         }
  430.         }
  431.         else {
  432.         while (s < bufend && isSPACE(*s))
  433.             s++;
  434.         if (*s == ':')    /* for csh's that have to exec sh scripts */
  435.             s++;
  436.         }
  437.     }
  438.     goto retry;
  439.     case ' ': case '\t': case '\f': case '\r': case 013:
  440.     s++;
  441.     goto retry;
  442.     case '#':
  443.     if (preprocess && s == str_get(linestr) &&
  444.            s[1] == ' ' && (isDIGIT(s[2]) || strnEQ(s+2,"line ",5)) ) {
  445.         while (*s && !isDIGIT(*s))
  446.         s++;
  447.         curcmd->c_line = atoi(s)-1;
  448.         while (isDIGIT(*s))
  449.         s++;
  450.         d = bufend;
  451.         while (s < d && isSPACE(*s)) s++;
  452.         s[strlen(s)-1] = '\0';    /* wipe out newline */
  453.         if (*s == '"') {
  454.         s++;
  455.         s[strlen(s)-1] = '\0';    /* wipe out trailing quote */
  456.         }
  457.         if (*s)
  458.         curcmd->c_filestab = fstab(s);
  459.         else
  460.         curcmd->c_filestab = fstab(origfilename);
  461.         oldoldbufptr = oldbufptr = s = str_get(linestr);
  462.     }
  463.     /* FALL THROUGH */
  464.     case '\n':
  465.     if (in_eval && !rsfp) {
  466.         d = bufend;
  467.         while (s < d && *s != '\n')
  468.         s++;
  469.         if (s < d)
  470.         s++;
  471.         if (in_format) {
  472.         bufptr = s;
  473.         yylval.formval = load_format();
  474.         in_format = FALSE;
  475.         oldoldbufptr = oldbufptr = s = bufptr + 1;
  476.         TERM(FORMLIST);
  477.         }
  478.         curcmd->c_line++;
  479.     }
  480.     else {
  481.         *s = '\0';
  482.         bufend = s;
  483.     }
  484.     goto retry;
  485.     case '-':
  486.     if (s[1] && isALPHA(s[1]) && !isALPHA(s[2])) {
  487.         s++;
  488.         last_uni = oldbufptr;
  489.         switch (*s++) {
  490.         case 'r': FTST(O_FTEREAD);
  491.         case 'w': FTST(O_FTEWRITE);
  492.         case 'x': FTST(O_FTEEXEC);
  493.         case 'o': FTST(O_FTEOWNED);
  494.         case 'R': FTST(O_FTRREAD);
  495.         case 'W': FTST(O_FTRWRITE);
  496.         case 'X': FTST(O_FTREXEC);
  497.         case 'O': FTST(O_FTROWNED);
  498.         case 'e': FTST(O_FTIS);
  499.         case 'z': FTST(O_FTZERO);
  500.         case 's': FTST(O_FTSIZE);
  501.         case 'f': FTST(O_FTFILE);
  502.         case 'd': FTST(O_FTDIR);
  503.         case 'l': FTST(O_FTLINK);
  504.         case 'p': FTST(O_FTPIPE);
  505.         case 'S': FTST(O_FTSOCK);
  506.         case 'u': FTST(O_FTSUID);
  507.         case 'g': FTST(O_FTSGID);
  508.         case 'k': FTST(O_FTSVTX);
  509.         case 'b': FTST(O_FTBLK);
  510.         case 'c': FTST(O_FTCHR);
  511.         case 't': FTST(O_FTTTY);
  512.         case 'T': FTST(O_FTTEXT);
  513.         case 'B': FTST(O_FTBINARY);
  514.         case 'M': stabent("\024",TRUE); FTST(O_FTMTIME);
  515.         case 'A': stabent("\024",TRUE); FTST(O_FTATIME);
  516.         case 'C': stabent("\024",TRUE); FTST(O_FTCTIME);
  517.         default:
  518.         s -= 2;
  519.         break;
  520.         }
  521.     }
  522.     tmp = *s++;
  523.     if (*s == tmp) {
  524.         s++;
  525.         RETURN(DEC);
  526.     }
  527.     if (expectterm) {
  528.         if (isSPACE(*s) || !isSPACE(*bufptr))
  529.         check_uni();
  530.         OPERATOR('-');
  531.     }
  532.     else
  533.         AOP(O_SUBTRACT);
  534.     case '+':
  535.     tmp = *s++;
  536.     if (*s == tmp) {
  537.         s++;
  538.         RETURN(INC);
  539.     }
  540.     if (expectterm) {
  541.         if (isSPACE(*s) || !isSPACE(*bufptr))
  542.         check_uni();
  543.         OPERATOR('+');
  544.     }
  545.     else
  546.         AOP(O_ADD);
  547.  
  548.     case '*':
  549.     if (expectterm) {
  550.         check_uni();
  551.         s = scanident(s,bufend,tokenbuf);
  552.         yylval.stabval = stabent(tokenbuf,TRUE);
  553.         TERM(STAR);
  554.     }
  555.     tmp = *s++;
  556.     if (*s == tmp) {
  557.         s++;
  558.         OPERATOR(POW);
  559.     }
  560.     MOP(O_MULTIPLY);
  561.     case '%':
  562.     if (expectterm) {
  563.         if (!isALPHA(s[1]))
  564.         check_uni();
  565.         s = scanident(s,bufend,tokenbuf);
  566.         yylval.stabval = hadd(stabent(tokenbuf,TRUE));
  567.         TERM(HSH);
  568.     }
  569.     s++;
  570.     MOP(O_MODULO);
  571.  
  572.     case '^':
  573.     case '~':
  574.     case '(':
  575.     case ',':
  576.     case ':':
  577.     case '[':
  578.     tmp = *s++;
  579.     OPERATOR(tmp);
  580.     case '{':
  581.     tmp = *s++;
  582.     yylval.ival = curcmd->c_line;
  583.     if (isSPACE(*s) || *s == '#')
  584.         cmdline = NOLINE;   /* invalidate current command line number */
  585.     expectterm = 2;
  586.     RETURN(tmp);
  587.     case ';':
  588.     if (curcmd->c_line < cmdline)
  589.         cmdline = curcmd->c_line;
  590.     tmp = *s++;
  591.     OPERATOR(tmp);
  592.     case ')':
  593.     case ']':
  594.     tmp = *s++;
  595.     TERM(tmp);
  596.     case '}':
  597.     *s |= 128;
  598.     RETURN(';');
  599.     case '&':
  600.     s++;
  601.     tmp = *s++;
  602.     if (tmp == '&')
  603.         OPERATOR(ANDAND);
  604.     s--;
  605.     if (expectterm) {
  606.         d = bufend;
  607.         while (s < d && isSPACE(*s))
  608.         s++;
  609.         if (isALPHA(*s) || *s == '_' || *s == '\'')
  610.         *(--s) = '\\';    /* force next ident to WORD */
  611.         else
  612.         check_uni();
  613.         OPERATOR(AMPER);
  614.     }
  615.     OPERATOR('&');
  616.     case '|':
  617.     s++;
  618.     tmp = *s++;
  619.     if (tmp == '|')
  620.         OPERATOR(OROR);
  621.     s--;
  622.     OPERATOR('|');
  623.     case '=':
  624.     s++;
  625.     tmp = *s++;
  626.     if (tmp == '=')
  627.         EOP(O_EQ);
  628.     if (tmp == '~')
  629.         OPERATOR(MATCH);
  630.     s--;
  631.     OPERATOR('=');
  632.     case '!':
  633.     s++;
  634.     tmp = *s++;
  635.     if (tmp == '=')
  636.         EOP(O_NE);
  637.     if (tmp == '~')
  638.         OPERATOR(NMATCH);
  639.     s--;
  640.     OPERATOR('!');
  641.     case '<':
  642.     if (expectterm) {
  643.         if (s[1] != '<' && !index(s,'>'))
  644.         check_uni();
  645.         s = scanstr(s, SCAN_DEF);
  646.         TERM(RSTRING);
  647.     }
  648.     s++;
  649.     tmp = *s++;
  650.     if (tmp == '<')
  651.         OPERATOR(LS);
  652.     if (tmp == '=') {
  653.         tmp = *s++;
  654.         if (tmp == '>')
  655.         EOP(O_NCMP);
  656.         s--;
  657.         ROP(O_LE);
  658.     }
  659.     s--;
  660.     ROP(O_LT);
  661.     case '>':
  662.     s++;
  663.     tmp = *s++;
  664.     if (tmp == '>')
  665.         OPERATOR(RS);
  666.     if (tmp == '=')
  667.         ROP(O_GE);
  668.     s--;
  669.     ROP(O_GT);
  670.  
  671. #define SNARFWORD \
  672.     d = tokenbuf; \
  673.     while (isALNUM(*s) || *s == '\'') \
  674.         *d++ = *s++; \
  675.     while (d[-1] == '\'') \
  676.         d--,s--; \
  677.     *d = '\0'; \
  678.     d = tokenbuf;
  679.  
  680.     case '$':
  681.     if (s[1] == '#' && (isALPHA(s[2]) || s[2] == '_')) {
  682.         s++;
  683.         s = scanident(s,bufend,tokenbuf);
  684.         yylval.stabval = aadd(stabent(tokenbuf,TRUE));
  685.         TERM(ARYLEN);
  686.     }
  687.     d = s;
  688.     s = scanident(s,bufend,tokenbuf);
  689.     if (reparse) {        /* turn ${foo[bar]} into ($foo[bar]) */
  690.       do_reparse:
  691.         s[-1] = ')';
  692.         s = d;
  693.         s[1] = s[0];
  694.         s[0] = '(';
  695.         goto retry;
  696.     }
  697.     yylval.stabval = stabent(tokenbuf,TRUE);
  698.     expectterm = FALSE;
  699.     if (isSPACE(*s) && oldoldbufptr && oldoldbufptr < bufptr) {
  700.         s++;
  701.         while (isSPACE(*oldoldbufptr))
  702.         oldoldbufptr++;
  703.         if (*oldoldbufptr == 'p' && strnEQ(oldoldbufptr,"print",5)) {
  704.         if (index("&*<%", *s) && isALPHA(s[1]))
  705.             expectterm = TRUE;        /* e.g. print $fh &sub */
  706.         else if (*s == '.' && isDIGIT(s[1]))
  707.             expectterm = TRUE;        /* e.g. print $fh .3 */
  708.         else if (index("/?-+", *s) && !isSPACE(s[1]))
  709.             expectterm = TRUE;        /* e.g. print $fh -1 */
  710.         }
  711.     }
  712.     RETURN(REG);
  713.  
  714.     case '@':
  715.     d = s;
  716.     s = scanident(s,bufend,tokenbuf);
  717.     if (reparse)
  718.         goto do_reparse;
  719.     yylval.stabval = aadd(stabent(tokenbuf,TRUE));
  720.     TERM(ARY);
  721.  
  722.     case '/':            /* may either be division or pattern */
  723.     case '?':            /* may either be conditional or pattern */
  724.     if (expectterm) {
  725.         check_uni();
  726.         s = scanpat(s);
  727.         TERM(PATTERN);
  728.     }
  729.     tmp = *s++;
  730.     if (tmp == '/')
  731.         MOP(O_DIVIDE);
  732.     OPERATOR(tmp);
  733.  
  734.     case '.':
  735.     if (!expectterm || !isDIGIT(s[1])) {
  736.         tmp = *s++;
  737.         if (*s == tmp) {
  738.         s++;
  739.         if (*s == tmp) {
  740.             s++;
  741.             yylval.ival = 0;
  742.         }
  743.         else
  744.             yylval.ival = AF_COMMON;
  745.         OPERATOR(DOTDOT);
  746.         }
  747.         if (expectterm)
  748.         check_uni();
  749.         AOP(O_CONCAT);
  750.     }
  751.     /* FALL THROUGH */
  752.     case '0': case '1': case '2': case '3': case '4':
  753.     case '5': case '6': case '7': case '8': case '9':
  754.     case '\'': case '"': case '`':
  755.     s = scanstr(s, SCAN_DEF);
  756.     TERM(RSTRING);
  757.  
  758.     case '\\':    /* some magic to force next word to be a WORD */
  759.     s++;    /* used by do and sub to force a separate namespace */
  760.     if (!isALPHA(*s) && *s != '_' && *s != '\'') {
  761.         warn("Spurious backslash ignored");
  762.         goto retry;
  763.     }
  764.     /* FALL THROUGH */
  765.     case '_':
  766.     SNARFWORD;
  767.     if (d[1] == '_') {
  768.         if (strEQ(d,"__LINE__") || strEQ(d,"__FILE__")) {
  769.         ARG *arg = op_new(1);
  770.  
  771.         yylval.arg = arg;
  772.         arg->arg_type = O_ITEM;
  773.         if (d[2] == 'L')
  774.             (void)sprintf(tokenbuf,"%ld",(long)curcmd->c_line);
  775.         else
  776.             strcpy(tokenbuf, stab_val(curcmd->c_filestab)->str_ptr);
  777.         arg[1].arg_type = A_SINGLE;
  778.         arg[1].arg_ptr.arg_str = str_make(tokenbuf,strlen(tokenbuf));
  779.         TERM(RSTRING);
  780.         }
  781.         else if (strEQ(d,"__END__")) {
  782.         STAB *stab;
  783.         int fd;
  784.  
  785.         /*SUPPRESS 560*/
  786.         if (!in_eval && (stab = stabent("DATA",FALSE))) {
  787.             stab->str_pok |= SP_MULTI;
  788.             if (!stab_io(stab))
  789.             stab_io(stab) = stio_new();
  790.             stab_io(stab)->ifp = rsfp;
  791. #if defined(HAS_FCNTL) && defined(F_SETFD)
  792.             fd = fileno(rsfp);
  793.             fcntl(fd,F_SETFD,fd >= 3);
  794. #endif
  795.             if (preprocess)
  796.             stab_io(stab)->type = '|';
  797.             else if ((FILE*)rsfp == stdin)
  798.             stab_io(stab)->type = '-';
  799.             else
  800.             stab_io(stab)->type = '<';
  801.             rsfp = Nullfp;
  802.         }
  803.         goto fake_eof;
  804.         }
  805.     }
  806.     break;
  807.     case 'a': case 'A':
  808.     SNARFWORD;
  809.     if (strEQ(d,"alarm"))
  810.         UNI(O_ALARM);
  811.     if (strEQ(d,"accept"))
  812.         FOP22(O_ACCEPT);
  813. #ifdef macintosh
  814.     if (strEQ(d,"answer"))
  815.         MIN1(O_ANSWER);
  816.     if (strEQ(d,"ask"))
  817.         FUN12(O_ASK);
  818. #endif
  819.     if (strEQ(d,"atan2"))
  820.         FUN2(O_ATAN2);
  821.     break;
  822.     case 'b': case 'B':
  823.     SNARFWORD;
  824.     if (strEQ(d,"bind"))
  825.         FOP2(O_BIND);
  826.     if (strEQ(d,"binmode"))
  827.         FOP(O_BINMODE);
  828.     break;
  829.     case 'c': case 'C':
  830.     SNARFWORD;
  831.     if (strEQ(d,"chop"))
  832.         LFUN(O_CHOP);
  833.     if (strEQ(d,"continue"))
  834.         OPERATOR(CONTINUE);
  835.     if (strEQ(d,"chdir")) {
  836.         (void)stabent("ENV",TRUE);    /* may use HOME */
  837.         UNI(O_CHDIR);
  838.     }
  839.     if (strEQ(d,"close"))
  840.         FOP(O_CLOSE);
  841.     if (strEQ(d,"closedir"))
  842.         FOP(O_CLOSEDIR);
  843.     if (strEQ(d,"cmp"))
  844.         EOP(O_SCMP);
  845.     if (strEQ(d,"caller"))
  846.         UNI(O_CALLER);
  847.     if (strEQ(d,"crypt")) {
  848. #ifdef FCRYPT
  849.         static int cryptseen = 0;
  850.  
  851.         if (!cryptseen++)
  852.         init_des();
  853. #endif
  854.         FUN2(O_CRYPT);
  855.     }
  856.     if (strEQ(d,"chmod"))
  857.         LOP(O_CHMOD);
  858.     if (strEQ(d,"chown"))
  859.         LOP(O_CHOWN);
  860.     if (strEQ(d,"connect"))
  861.         FOP2(O_CONNECT);
  862.     if (strEQ(d,"cos"))
  863.         UNI(O_COS);
  864.     if (strEQ(d,"chroot"))
  865.         UNI(O_CHROOT);
  866. #ifdef macintosh
  867.     if (strEQ(d,"choose"))
  868.         CHOOS(O_CHOOSE);
  869. #endif
  870.     break;
  871.     case 'd': case 'D':
  872.     SNARFWORD;
  873.     if (strEQ(d,"do")) {
  874.         d = bufend;
  875.         while (s < d && isSPACE(*s))
  876.         s++;
  877.         if (isALPHA(*s) || *s == '_')
  878.         *(--s) = '\\';    /* force next ident to WORD */
  879.         OPERATOR(DO);
  880.     }
  881.     if (strEQ(d,"die"))
  882.         LOP(O_DIE);
  883.     if (strEQ(d,"defined"))
  884.         LFUN(O_DEFINED);
  885.     if (strEQ(d,"delete"))
  886.         OPERATOR(DELETE);
  887.     if (strEQ(d,"dbmopen"))
  888.         HFUN3(O_DBMOPEN);
  889.     if (strEQ(d,"dbmclose"))
  890.         HFUN(O_DBMCLOSE);
  891.     if (strEQ(d,"dump"))
  892.         LOOPX(O_DUMP);
  893.     break;
  894.     case 'e': case 'E':
  895.     SNARFWORD;
  896.     if (strEQ(d,"else"))
  897.         OPERATOR(ELSE);
  898.     if (strEQ(d,"elsif")) {
  899.         yylval.ival = curcmd->c_line;
  900.         OPERATOR(ELSIF);
  901.     }
  902.     if (strEQ(d,"eq") || strEQ(d,"EQ"))
  903.         EOP(O_SEQ);
  904.     if (strEQ(d,"exit"))
  905.         UNI(O_EXIT);
  906.     if (strEQ(d,"eval")) {
  907.         allstabs = TRUE;        /* must initialize everything since */
  908.         UNI(O_EVAL);        /* we don't know what will be used */
  909.     }
  910.     if (strEQ(d,"eof"))
  911.         FOP(O_EOF);
  912.     if (strEQ(d,"exp"))
  913.         UNI(O_EXP);
  914.     if (strEQ(d,"each"))
  915.         HFUN(O_EACH);
  916.     if (strEQ(d,"exec")) {
  917.         set_csh();
  918.         LOP(O_EXEC_OP);
  919.     }
  920.     if (strEQ(d,"endhostent"))
  921.         FUN0(O_EHOSTENT);
  922.     if (strEQ(d,"endnetent"))
  923.         FUN0(O_ENETENT);
  924.     if (strEQ(d,"endservent"))
  925.         FUN0(O_ESERVENT);
  926.     if (strEQ(d,"endprotoent"))
  927.         FUN0(O_EPROTOENT);
  928.     if (strEQ(d,"endpwent"))
  929.         FUN0(O_EPWENT);
  930.     if (strEQ(d,"endgrent"))
  931.         FUN0(O_EGRENT);
  932.     break;
  933.     case 'f': case 'F':
  934.     SNARFWORD;
  935.     if (strEQ(d,"for") || strEQ(d,"foreach")) {
  936.         yylval.ival = curcmd->c_line;
  937.         while (s < bufend && isSPACE(*s))
  938.         s++;
  939.         if (isALPHA(*s))
  940.         fatal("Missing $ on loop variable");
  941.         OPERATOR(FOR);
  942.     }
  943.     if (strEQ(d,"format")) {
  944.         d = bufend;
  945.         while (s < d && isSPACE(*s))
  946.         s++;
  947.         if (isALPHA(*s) || *s == '_')
  948.         *(--s) = '\\';    /* force next ident to WORD */
  949.         in_format = TRUE;
  950.         allstabs = TRUE;        /* must initialize everything since */
  951.         OPERATOR(FORMAT);        /* we don't know what will be used */
  952.     }
  953.     if (strEQ(d,"fork"))
  954.         FUN0(O_FORK);
  955.     if (strEQ(d,"fcntl"))
  956.         FOP3(O_FCNTL);
  957.     if (strEQ(d,"fileno"))
  958.         FOP(O_FILENO);
  959.     if (strEQ(d,"flock"))
  960.         FOP2(O_FLOCK);
  961.     break;
  962.     case 'g': case 'G':
  963.     SNARFWORD;
  964.     if (strEQ(d,"gt") || strEQ(d,"GT"))
  965.         ROP(O_SGT);
  966.     if (strEQ(d,"ge") || strEQ(d,"GE"))
  967.         ROP(O_SGE);
  968.     if (strEQ(d,"grep"))
  969.         FL2(O_GREP);
  970.     if (strEQ(d,"goto"))
  971.         LOOPX(O_GOTO);
  972.     if (strEQ(d,"gmtime"))
  973.         UNI(O_GMTIME);
  974.     if (strEQ(d,"getc"))
  975.         FOP(O_GETC);
  976.     if (strnEQ(d,"get",3)) {
  977.         d += 3;
  978.         if (*d == 'p') {
  979.         if (strEQ(d,"ppid"))
  980.             FUN0(O_GETPPID);
  981.         if (strEQ(d,"pgrp"))
  982.             UNI(O_GETPGRP);
  983.         if (strEQ(d,"priority"))
  984.             FUN2(O_GETPRIORITY);
  985.         if (strEQ(d,"protobyname"))
  986.             UNI(O_GPBYNAME);
  987.         if (strEQ(d,"protobynumber"))
  988.             FUN1(O_GPBYNUMBER);
  989.         if (strEQ(d,"protoent"))
  990.             FUN0(O_GPROTOENT);
  991.         if (strEQ(d,"pwent"))
  992.             FUN0(O_GPWENT);
  993.         if (strEQ(d,"pwnam"))
  994.             FUN1(O_GPWNAM);
  995.         if (strEQ(d,"pwuid"))
  996.             FUN1(O_GPWUID);
  997.         if (strEQ(d,"peername"))
  998.             FOP(O_GETPEERNAME);
  999.         }
  1000.         else if (*d == 'h') {
  1001.         if (strEQ(d,"hostbyname"))
  1002.             UNI(O_GHBYNAME);
  1003.         if (strEQ(d,"hostbyaddr"))
  1004.             FUN2(O_GHBYADDR);
  1005.         if (strEQ(d,"hostent"))
  1006.             FUN0(O_GHOSTENT);
  1007.         }
  1008.         else if (*d == 'n') {
  1009.         if (strEQ(d,"netbyname"))
  1010.             UNI(O_GNBYNAME);
  1011.         if (strEQ(d,"netbyaddr"))
  1012.             FUN2(O_GNBYADDR);
  1013.         if (strEQ(d,"netent"))
  1014.             FUN0(O_GNETENT);
  1015.         }
  1016.         else if (*d == 's') {
  1017.         if (strEQ(d,"servbyname"))
  1018.             FUN2(O_GSBYNAME);
  1019.         if (strEQ(d,"servbyport"))
  1020.             FUN2(O_GSBYPORT);
  1021.         if (strEQ(d,"servent"))
  1022.             FUN0(O_GSERVENT);
  1023.         if (strEQ(d,"sockname"))
  1024.             FOP(O_GETSOCKNAME);
  1025.         if (strEQ(d,"sockopt"))
  1026.             FOP3(O_GSOCKOPT);
  1027.         }
  1028.         else if (*d == 'g') {
  1029.         if (strEQ(d,"grent"))
  1030.             FUN0(O_GGRENT);
  1031.         if (strEQ(d,"grnam"))
  1032.             FUN1(O_GGRNAM);
  1033.         if (strEQ(d,"grgid"))
  1034.             FUN1(O_GGRGID);
  1035.         }
  1036.         else if (*d == 'l') {
  1037.         if (strEQ(d,"login"))
  1038.             FUN0(O_GETLOGIN);
  1039.         }
  1040.         d -= 3;
  1041.     }
  1042.     break;
  1043.     case 'h': case 'H':
  1044.     SNARFWORD;
  1045.     if (strEQ(d,"hex"))
  1046.         UNI(O_HEX);
  1047.     break;
  1048.     case 'i': case 'I':
  1049.     SNARFWORD;
  1050.     if (strEQ(d,"if")) {
  1051.         yylval.ival = curcmd->c_line;
  1052.         OPERATOR(IF);
  1053.     }
  1054.     if (strEQ(d,"index"))
  1055.         FUN2x(O_INDEX);
  1056.     if (strEQ(d,"int"))
  1057.         UNI(O_INT);
  1058.     if (strEQ(d,"ioctl"))
  1059.         FOP3(O_IOCTL);
  1060.     break;
  1061.     case 'j': case 'J':
  1062.     SNARFWORD;
  1063.     if (strEQ(d,"join"))
  1064.         FL2(O_JOIN);
  1065.     break;
  1066.     case 'k': case 'K':
  1067.     SNARFWORD;
  1068.     if (strEQ(d,"keys"))
  1069.         HFUN(O_KEYS);
  1070.     if (strEQ(d,"kill"))
  1071.         LOP(O_KILL);
  1072.     break;
  1073.     case 'l': case 'L':
  1074.     SNARFWORD;
  1075.     if (strEQ(d,"last"))
  1076.         LOOPX(O_LAST);
  1077.     if (strEQ(d,"local"))
  1078.         OPERATOR(LOCAL);
  1079.     if (strEQ(d,"length"))
  1080.         UNI(O_LENGTH);
  1081.     if (strEQ(d,"lt") || strEQ(d,"LT"))
  1082.         ROP(O_SLT);
  1083.     if (strEQ(d,"le") || strEQ(d,"LE"))
  1084.         ROP(O_SLE);
  1085.     if (strEQ(d,"localtime"))
  1086.         UNI(O_LOCALTIME);
  1087.     if (strEQ(d,"log"))
  1088.         UNI(O_LOG);
  1089.     if (strEQ(d,"link"))
  1090.         FUN2(O_LINK);
  1091.     if (strEQ(d,"listen"))
  1092.         FOP2(O_LISTEN);
  1093.     if (strEQ(d,"lstat"))
  1094.         FOP(O_LSTAT);
  1095.     break;
  1096.     case 'm': case 'M':
  1097.     if (s[1] == '\'') {
  1098.         d = "m";
  1099.         s++;
  1100.     }
  1101.     else {
  1102.         SNARFWORD;
  1103.     }
  1104.     if (strEQ(d,"m")) {
  1105.         s = scanpat(s-1);
  1106.         if (yylval.arg)
  1107.         TERM(PATTERN);
  1108.         else
  1109.         RETURN(1);    /* force error */
  1110.     }
  1111.     switch (d[1]) {
  1112.     case 'k':
  1113.         if (strEQ(d,"mkdir"))
  1114.         FUN2(O_MKDIR);
  1115.         break;
  1116.     case 's':
  1117.         if (strEQ(d,"msgctl"))
  1118.         FUN3(O_MSGCTL);
  1119.         if (strEQ(d,"msgget"))
  1120.         FUN2(O_MSGGET);
  1121.         if (strEQ(d,"msgrcv"))
  1122.         FUN5(O_MSGRCV);
  1123.         if (strEQ(d,"msgsnd"))
  1124.         FUN3(O_MSGSND);
  1125.         break;
  1126.     }
  1127.     break;
  1128.     case 'n': case 'N':
  1129.     SNARFWORD;
  1130.     if (strEQ(d,"next"))
  1131.         LOOPX(O_NEXT);
  1132.     if (strEQ(d,"ne") || strEQ(d,"NE"))
  1133.         EOP(O_SNE);
  1134.     break;
  1135.     case 'o': case 'O':
  1136.     SNARFWORD;
  1137.     if (strEQ(d,"open"))
  1138.         OPERATOR(OPEN);
  1139.     if (strEQ(d,"ord"))
  1140.         UNI(O_ORD);
  1141.     if (strEQ(d,"oct"))
  1142.         UNI(O_OCT);
  1143.     if (strEQ(d,"opendir"))
  1144.         FOP2(O_OPEN_DIR);
  1145.     break;
  1146.     case 'p': case 'P':
  1147.     SNARFWORD;
  1148.     if (strEQ(d,"print")) {
  1149.         checkcomma(s,d,"filehandle");
  1150.         LOP(O_PRINT);
  1151.     }
  1152.     if (strEQ(d,"printf")) {
  1153.         checkcomma(s,d,"filehandle");
  1154.         LOP(O_PRTF);
  1155.     }
  1156.     if (strEQ(d,"push")) {
  1157.         yylval.ival = O_PUSH;
  1158.         OPERATOR(PUSH);
  1159.     }
  1160.     if (strEQ(d,"pop"))
  1161.         OPERATOR(POP);
  1162.     if (strEQ(d,"pack"))
  1163.         FL2(O_PACK);
  1164.     if (strEQ(d,"package"))
  1165.         OPERATOR(PACKAGE);
  1166. #ifdef macintosh
  1167.     if (strEQ(d,"pick"))
  1168.         MIN1(O_PICK);
  1169. #endif
  1170.     if (strEQ(d,"pipe"))
  1171.         FOP22(O_PIPE_OP);
  1172.     break;
  1173.     case 'q': case 'Q':
  1174.     SNARFWORD;
  1175.     if (strEQ(d,"q")) {
  1176.         s = scanstr(s-1, SCAN_DEF);
  1177.         TERM(RSTRING);
  1178.     }
  1179.     if (strEQ(d,"qq")) {
  1180.         s = scanstr(s-2, SCAN_DEF);
  1181.         TERM(RSTRING);
  1182.     }
  1183.     if (strEQ(d,"qx")) {
  1184.         s = scanstr(s-2, SCAN_DEF);
  1185.         TERM(RSTRING);
  1186.     }
  1187.     break;
  1188.     case 'r': case 'R':
  1189.     SNARFWORD;
  1190.     if (strEQ(d,"return"))
  1191.         OLDLOP(O_RETURN);
  1192.     if (strEQ(d,"require")) {
  1193.         allstabs = TRUE;        /* must initialize everything since */
  1194.         UNI(O_REQUIRE);        /* we don't know what will be used */
  1195.     }
  1196.     if (strEQ(d,"reset"))
  1197.         UNI(O_RESET);
  1198.     if (strEQ(d,"redo"))
  1199.         LOOPX(O_REDO);
  1200.     if (strEQ(d,"rename"))
  1201.         FUN2(O_RENAME);
  1202.     if (strEQ(d,"rand"))
  1203.         UNI(O_RAND);
  1204.     if (strEQ(d,"rmdir"))
  1205.         UNI(O_RMDIR);
  1206.     if (strEQ(d,"rindex"))
  1207.         FUN2x(O_RINDEX);
  1208.     if (strEQ(d,"read"))
  1209.         FOP3(O_READ);
  1210.     if (strEQ(d,"readdir"))
  1211.         FOP(O_READDIR);
  1212.     if (strEQ(d,"rewinddir"))
  1213.         FOP(O_REWINDDIR);
  1214.     if (strEQ(d,"recv"))
  1215.         FOP4(O_RECV);
  1216.     if (strEQ(d,"reverse"))
  1217.         LOP(O_REVERSE);
  1218.     if (strEQ(d,"readlink"))
  1219.         UNI(O_READLINK);
  1220.     break;
  1221.     case 's': case 'S':
  1222.     if (s[1] == '\'') {
  1223.         d = "s";
  1224.         s++;
  1225.     }
  1226.     else {
  1227.         SNARFWORD;
  1228.     }
  1229.     if (strEQ(d,"s")) {
  1230.         s = scansubst(s);
  1231.         if (yylval.arg)
  1232.         TERM(SUBST);
  1233.         else
  1234.         RETURN(1);    /* force error */
  1235.     }
  1236.     switch (d[1]) {
  1237.     case 'a':
  1238.     case 'b':
  1239.         break;
  1240.     case 'c':
  1241.         if (strEQ(d,"scalar"))
  1242.         UNI(O_SCALAR);
  1243.         break;
  1244.     case 'd':
  1245.         break;
  1246.     case 'e':
  1247.         if (strEQ(d,"select"))
  1248.         OPERATOR(SSELECT);
  1249.         if (strEQ(d,"seek"))
  1250.         FOP3(O_SEEK);
  1251.         if (strEQ(d,"semctl"))
  1252.         FUN4(O_SEMCTL);
  1253.         if (strEQ(d,"semget"))
  1254.         FUN3(O_SEMGET);
  1255.         if (strEQ(d,"semop"))
  1256.         FUN2(O_SEMOP);
  1257.         if (strEQ(d,"send"))
  1258.         FOP3(O_SEND);
  1259.         if (strEQ(d,"setpgrp"))
  1260.         FUN2(O_SETPGRP);
  1261.         if (strEQ(d,"setpriority"))
  1262.         FUN3(O_SETPRIORITY);
  1263.         if (strEQ(d,"sethostent"))
  1264.         FUN1(O_SHOSTENT);
  1265.         if (strEQ(d,"setnetent"))
  1266.         FUN1(O_SNETENT);
  1267.         if (strEQ(d,"setservent"))
  1268.         FUN1(O_SSERVENT);
  1269.         if (strEQ(d,"setprotoent"))
  1270.         FUN1(O_SPROTOENT);
  1271.         if (strEQ(d,"setpwent"))
  1272.         FUN0(O_SPWENT);
  1273.         if (strEQ(d,"setgrent"))
  1274.         FUN0(O_SGRENT);
  1275.         if (strEQ(d,"seekdir"))
  1276.         FOP2(O_SEEKDIR);
  1277.         if (strEQ(d,"setsockopt"))
  1278.         FOP4(O_SSOCKOPT);
  1279.         break;
  1280.     case 'f':
  1281.     case 'g':
  1282.         break;
  1283.     case 'h':
  1284.         if (strEQ(d,"shift"))
  1285.         TERM(SHIFT);
  1286.         if (strEQ(d,"shmctl"))
  1287.         FUN3(O_SHMCTL);
  1288.         if (strEQ(d,"shmget"))
  1289.         FUN3(O_SHMGET);
  1290.         if (strEQ(d,"shmread"))
  1291.         FUN4(O_SHMREAD);
  1292.         if (strEQ(d,"shmwrite"))
  1293.         FUN4(O_SHMWRITE);
  1294.         if (strEQ(d,"shutdown"))
  1295.         FOP2(O_SHUTDOWN);
  1296.         break;
  1297.     case 'i':
  1298.         if (strEQ(d,"sin"))
  1299.         UNI(O_SIN);
  1300.         break;
  1301.     case 'j':
  1302.     case 'k':
  1303.         break;
  1304.     case 'l':
  1305.         if (strEQ(d,"sleep"))
  1306.         UNI(O_SLEEP);
  1307.         break;
  1308.     case 'm':
  1309.     case 'n':
  1310.         break;
  1311.     case 'o':
  1312.         if (strEQ(d,"socket"))
  1313.         FOP4(O_SOCKET);
  1314.         if (strEQ(d,"socketpair"))
  1315.         FOP25(O_SOCKPAIR);
  1316.         if (strEQ(d,"sort")) {
  1317.         checkcomma(s,d,"subroutine name");
  1318.         d = bufend;
  1319.         while (s < d && isSPACE(*s)) s++;
  1320.         if (*s == ';' || *s == ')')        /* probably a close */
  1321.             fatal("sort is now a reserved word");
  1322.         if (isALPHA(*s) || *s == '_') {
  1323.             /*SUPPRESS 530*/
  1324.             for (d = s; isALNUM(*d); d++) ;
  1325.             strncpy(tokenbuf,s,d-s);
  1326.             tokenbuf[d-s] = '\0';
  1327.             if (strNE(tokenbuf,"keys") &&
  1328.             strNE(tokenbuf,"values") &&
  1329.             strNE(tokenbuf,"split") &&
  1330.             strNE(tokenbuf,"grep") &&
  1331.             strNE(tokenbuf,"readdir") &&
  1332.             strNE(tokenbuf,"unpack") &&
  1333.             strNE(tokenbuf,"do") &&
  1334.             strNE(tokenbuf,"eval") &&
  1335.             (d >= bufend || isSPACE(*d)) )
  1336.             *(--s) = '\\';    /* force next ident to WORD */
  1337.         }
  1338.         LOP(O_SORT);
  1339.         }
  1340.         break;
  1341.     case 'p':
  1342.         if (strEQ(d,"split"))
  1343.         TERM(SPLIT);
  1344.         if (strEQ(d,"sprintf"))
  1345.         FL(O_SPRINTF);
  1346.         if (strEQ(d,"splice")) {
  1347.         yylval.ival = O_SPLICE;
  1348.         OPERATOR(PUSH);
  1349.         }
  1350.         break;
  1351.     case 'q':
  1352.         if (strEQ(d,"sqrt"))
  1353.         UNI(O_SQRT);
  1354.         break;
  1355.     case 'r':
  1356.         if (strEQ(d,"srand"))
  1357.         UNI(O_SRAND);
  1358.         break;
  1359.     case 's':
  1360.         break;
  1361.     case 't':
  1362.         if (strEQ(d,"stat"))
  1363.         FOP(O_STAT);
  1364.         if (strEQ(d,"study")) {
  1365.         sawstudy++;
  1366.         LFUN(O_STUDY);
  1367.         }
  1368.         break;
  1369.     case 'u':
  1370.         if (strEQ(d,"substr"))
  1371.         FUN2x(O_SUBSTR);
  1372.         if (strEQ(d,"sub")) {
  1373.         yylval.ival = savestack->ary_fill; /* restore stuff on reduce */
  1374.         savelong(&subline);
  1375.         saveitem(subname);
  1376.  
  1377.         subline = curcmd->c_line;
  1378.         d = bufend;
  1379.         while (s < d && isSPACE(*s))
  1380.             s++;
  1381.         if (isALPHA(*s) || *s == '_' || *s == '\'') {
  1382.             str_sset(subname,curstname);
  1383.             str_ncat(subname,"'",1);
  1384.             for (d = s+1; isALNUM(*d) || *d == '\''; d++)
  1385.             /*SUPPRESS 530*/
  1386.             ;
  1387.             if (d[-1] == '\'')
  1388.             d--;
  1389.             str_ncat(subname,s,d-s);
  1390.             *(--s) = '\\';    /* force next ident to WORD */
  1391.         }
  1392.         else
  1393.             str_set(subname,"?");
  1394.         OPERATOR(SUB);
  1395.         }
  1396.         break;
  1397.     case 'v':
  1398.     case 'w':
  1399.     case 'x':
  1400.         break;
  1401.     case 'y':
  1402.         if (strEQ(d,"system")) {
  1403.         set_csh();
  1404.         LOP(O_SYSTEM);
  1405.         }
  1406.         if (strEQ(d,"symlink"))
  1407.         FUN2(O_SYMLINK);
  1408.         if (strEQ(d,"syscall"))
  1409.         LOP(O_SYSCALL);
  1410.         if (strEQ(d,"sysread"))
  1411.         FOP3(O_SYSREAD);
  1412.         if (strEQ(d,"syswrite"))
  1413.         FOP3(O_SYSWRITE);
  1414.         break;
  1415.     case 'z':
  1416.         break;
  1417.     }
  1418.     break;
  1419.     case 't': case 'T':
  1420.     SNARFWORD;
  1421.     if (strEQ(d,"tr")) {
  1422.         s = scantrans(s);
  1423.         if (yylval.arg)
  1424.         TERM(TRANS);
  1425.         else
  1426.         RETURN(1);    /* force error */
  1427.     }
  1428.     if (strEQ(d,"tell"))
  1429.         FOP(O_TELL);
  1430.     if (strEQ(d,"telldir"))
  1431.         FOP(O_TELLDIR);
  1432.     if (strEQ(d,"time"))
  1433.         FUN0(O_TIME);
  1434.     if (strEQ(d,"times"))
  1435.         FUN0(O_TMS);
  1436.     if (strEQ(d,"truncate"))
  1437.         FOP2(O_TRUNCATE);
  1438.     break;
  1439.     case 'u': case 'U':
  1440.     SNARFWORD;
  1441.     if (strEQ(d,"using"))
  1442.         OPERATOR(USING);
  1443.     if (strEQ(d,"until")) {
  1444.         yylval.ival = curcmd->c_line;
  1445.         OPERATOR(UNTIL);
  1446.     }
  1447.     if (strEQ(d,"unless")) {
  1448.         yylval.ival = curcmd->c_line;
  1449.         OPERATOR(UNLESS);
  1450.     }
  1451.     if (strEQ(d,"unlink"))
  1452.         LOP(O_UNLINK);
  1453.     if (strEQ(d,"undef"))
  1454.         LFUN(O_UNDEF);
  1455.     if (strEQ(d,"unpack"))
  1456.         FUN2(O_UNPACK);
  1457.     if (strEQ(d,"utime"))
  1458.         LOP(O_UTIME);
  1459.     if (strEQ(d,"umask"))
  1460.         UNI(O_UMASK);
  1461.     if (strEQ(d,"unshift")) {
  1462.         yylval.ival = O_UNSHIFT;
  1463.         OPERATOR(PUSH);
  1464.     }
  1465.     break;
  1466.     case 'v': case 'V':
  1467.     SNARFWORD;
  1468.     if (strEQ(d,"values"))
  1469.         HFUN(O_VALUES);
  1470.     if (strEQ(d,"vec")) {
  1471.         sawvec = TRUE;
  1472.         FUN3(O_VEC);
  1473.     }
  1474.     break;
  1475.     case 'w': case 'W':
  1476.     SNARFWORD;
  1477.     if (strEQ(d,"while")) {
  1478.         yylval.ival = curcmd->c_line;
  1479.         OPERATOR(WHILE);
  1480.     }
  1481.     if (strEQ(d,"warn"))
  1482.         LOP(O_WARN);
  1483.     if (strEQ(d,"wait"))
  1484.         FUN0(O_WAIT);
  1485.     if (strEQ(d,"waitpid"))
  1486.         FUN2(O_WAITPID);
  1487.     if (strEQ(d,"wantarray")) {
  1488.         yylval.arg = op_new(1);
  1489.         yylval.arg->arg_type = O_ITEM;
  1490.         yylval.arg[1].arg_type = A_WANTARRAY;
  1491.         TERM(RSTRING);
  1492.     }
  1493.     if (strEQ(d,"write"))
  1494.         FOP(O_WRITE);
  1495.     break;
  1496.     case 'x': case 'X':
  1497.     if (*s == 'x' && isDIGIT(s[1]) && !expectterm) {
  1498.         s++;
  1499.         MOP(O_REPEAT);
  1500.     }
  1501.     SNARFWORD;
  1502.     if (strEQ(d,"x")) {
  1503.         if (!expectterm)
  1504.         MOP(O_REPEAT);
  1505.         check_uni();
  1506.     }
  1507.     break;
  1508.     case 'y': case 'Y':
  1509.     if (s[1] == '\'') {
  1510.         d = "y";
  1511.         s++;
  1512.     }
  1513.     else {
  1514.         SNARFWORD;
  1515.     }
  1516.     if (strEQ(d,"y")) {
  1517.         s = scantrans(s);
  1518.         TERM(TRANS);
  1519.     }
  1520.     break;
  1521.     case 'z': case 'Z':
  1522.     SNARFWORD;
  1523.     break;
  1524.     }
  1525.     yylval.cval = savestr(d);
  1526.     if (expectterm == 2) {        /* special case: start of statement */
  1527.     while (isSPACE(*s)) s++;
  1528.     if (*s == ':') {
  1529.         s++;
  1530.         CLINE;
  1531.         OPERATOR(LABEL);
  1532.     }
  1533.     TERM(WORD);
  1534.     }
  1535.     expectterm = FALSE;
  1536.     if (oldoldbufptr && oldoldbufptr < bufptr) {
  1537.     while (isSPACE(*oldoldbufptr))
  1538.         oldoldbufptr++;
  1539.     if (*oldoldbufptr == 'p' && strnEQ(oldoldbufptr,"print",5))
  1540.         expectterm = TRUE;
  1541.     else if (*oldoldbufptr == 's' && strnEQ(oldoldbufptr,"sort",4))
  1542.         expectterm = TRUE;
  1543.     }
  1544.     return (CLINE, bufptr = s, (int)WORD);
  1545. }
  1546.  
  1547. void
  1548. checkcomma(s,name,what)
  1549. register char *s;
  1550. char *name;
  1551. char *what;
  1552. {
  1553.     char *w;
  1554.  
  1555.     if (dowarn && *s == ' ' && s[1] == '(') {
  1556.     w = index(s,')');
  1557.     if (w)
  1558.         for (w++; *w && isSPACE(*w); w++) ;
  1559.     if (!w || !*w || !index(";|}", *w))    /* an advisory hack only... */
  1560.         warn("%s (...) interpreted as function",name);
  1561.     }
  1562.     while (s < bufend && isSPACE(*s))
  1563.     s++;
  1564.     if (*s == '(')
  1565.     s++;
  1566.     while (s < bufend && isSPACE(*s))
  1567.     s++;
  1568.     if (isALPHA(*s) || *s == '_') {
  1569.     w = s++;
  1570.     while (isALNUM(*s))
  1571.         s++;
  1572.     while (s < bufend && isSPACE(*s))
  1573.         s++;
  1574.     if (*s == ',') {
  1575.         *s = '\0';
  1576.         w = instr(
  1577.           "tell eof times getlogin wait length shift umask getppid \
  1578.           cos exp int log rand sin sqrt ord wantarray",
  1579.           w);
  1580.         *s = ',';
  1581.         if (w)
  1582.         return;
  1583.         fatal("No comma allowed after %s", what);
  1584.     }
  1585.     }
  1586. }
  1587.  
  1588. char *
  1589. scanident(s,send,dest)
  1590. register char *s;
  1591. register char *send;
  1592. char *dest;
  1593. {
  1594.     register char *d;
  1595.     int brackets = 0;
  1596.  
  1597.     reparse = Nullch;
  1598.     s++;
  1599.     d = dest;
  1600.     if (isDIGIT(*s)) {
  1601.     while (isDIGIT(*s))
  1602.         *d++ = *s++;
  1603.     }
  1604.     else {
  1605.     while (isALNUM(*s) || *s == '\'')
  1606.         *d++ = *s++;
  1607.     }
  1608.     while (d > dest+1 && d[-1] == '\'')
  1609.     d--,s--;
  1610.     *d = '\0';
  1611.     d = dest;
  1612.     if (!*d) {
  1613.     *d = *s++;
  1614.     if (*d == '{' /* } */ ) {
  1615.         d = dest;
  1616.         brackets++;
  1617.         while (s < send && brackets) {
  1618.         if (!reparse && (d == dest || (*s && isALNUM(*s) ))) {
  1619.             *d++ = *s++;
  1620.             continue;
  1621.         }
  1622.         else if (!reparse)
  1623.             reparse = s;
  1624.         switch (*s++) {
  1625.         /* { */
  1626.         case '}':
  1627.             brackets--;
  1628.             if (reparse && reparse == s - 1)
  1629.             reparse = Nullch;
  1630.             break;
  1631.         case '{':   /* } */
  1632.             brackets++;
  1633.             break;
  1634.         }
  1635.         }
  1636.         *d = '\0';
  1637.         d = dest;
  1638.     }
  1639.     else
  1640.         d[1] = '\0';
  1641.     }
  1642.     if (*d == '^' && (isUPPER(*s) || index("[\\]^_?", *s))) {
  1643. #ifdef DEBUGGING
  1644.     if (*s == 'D')
  1645.         debug |= 32768;
  1646. #endif
  1647.     *d = *s++ ^ 64;
  1648.     }
  1649.     return s;
  1650. }
  1651.  
  1652. void
  1653. scanconst(spat,string,len)
  1654. SPAT *spat;
  1655. char *string;
  1656. int len;
  1657. {
  1658.     register STR *tmpstr;
  1659.     register char *t;
  1660.     register char *d;
  1661.     register char *e;
  1662.     char *origstring = string;
  1663.     static char *vert = "|";
  1664.  
  1665.     if (ninstr(string, string+len, vert, vert+1))
  1666.     return;
  1667.     if (*string == '^')
  1668.     string++, len--;
  1669.     tmpstr = Str_new(86,len);
  1670.     str_nset(tmpstr,string,len);
  1671.     t = str_get(tmpstr);
  1672.     e = t + len;
  1673.     tmpstr->str_u.str_useful = 100;
  1674.     for (d=t; d < e; ) {
  1675.     switch (*d) {
  1676.     case '{':
  1677.         if (isDIGIT(d[1]))
  1678.         e = d;
  1679.         else
  1680.         goto defchar;
  1681.         break;
  1682.     case '.': case '[': case '$': case '(': case ')': case '|': case '+':
  1683.     case '^':
  1684.         e = d;
  1685.         break;
  1686.     case '\\':
  1687.         if (d[1] && index("wWbB0123456789sSdDlLuUExc",d[1])) {
  1688.         e = d;
  1689.         break;
  1690.         }
  1691.         Move(d+1,d,e-d,char);
  1692.         e--;
  1693.         switch(*d) {
  1694.         case 'n':
  1695.         *d = '\n';
  1696.         break;
  1697.         case 't':
  1698.         *d = '\t';
  1699.         break;
  1700.         case 'f':
  1701.         *d = '\f';
  1702.         break;
  1703.         case 'r':
  1704.         *d = '\r';
  1705.         break;
  1706.         case 'e':
  1707.         *d = '\033';
  1708.         break;
  1709.         case 'a':
  1710.         *d = '\007';
  1711.         break;
  1712.         }
  1713.         /* FALL THROUGH */
  1714.     default:
  1715.       defchar:
  1716.         if (d[1] == '*' || (d[1] == '{' && d[2] == '0') || d[1] == '?') {
  1717.         e = d;
  1718.         break;
  1719.         }
  1720.         d++;
  1721.     }
  1722.     }
  1723.     if (d == t) {
  1724.     str_free(tmpstr);
  1725.     return;
  1726.     }
  1727.     *d = '\0';
  1728.     tmpstr->str_cur = d - t;
  1729.     if (d == t+len)
  1730.     spat->spat_flags |= SPAT_ALL;
  1731.     if (*origstring != '^')
  1732.     spat->spat_flags |= SPAT_SCANFIRST;
  1733.     spat->spat_short = tmpstr;
  1734.     spat->spat_slen = d - t;
  1735. }
  1736.  
  1737. char *
  1738. scanpat(s)
  1739. register char *s;
  1740. {
  1741.     register SPAT *spat;
  1742.     register char *d;
  1743.     register char *e;
  1744.     int len;
  1745.     SPAT savespat;
  1746.     STR *str = Str_new(93,0);
  1747.     char delim;
  1748.  
  1749.     Newz(801,spat,1,SPAT);
  1750.     spat->spat_next = curstash->tbl_spatroot;    /* link into spat list */
  1751.     curstash->tbl_spatroot = spat;
  1752.  
  1753.     switch (*s++) {
  1754.     case 'm':
  1755.     s++;
  1756.     break;
  1757.     case '/':
  1758.     break;
  1759.     case '?':
  1760.     spat->spat_flags |= SPAT_ONCE;
  1761.     break;
  1762.     default:
  1763.     fatal("panic: scanpat");
  1764.     }
  1765.     s = str_append_till(str,s,bufend,s[-1],patleave);
  1766.     if (s >= bufend) {
  1767.     str_free(str);
  1768.     yyerror("Search pattern not terminated");
  1769.     yylval.arg = Nullarg;
  1770.     return s;
  1771.     }
  1772.     delim = *s++;
  1773.     while (*s == 'i' || *s == 'o' || *s == 'g') {
  1774.     if (*s == 'i') {
  1775.         s++;
  1776.         sawi = TRUE;
  1777.         spat->spat_flags |= SPAT_FOLD;
  1778.     }
  1779.     if (*s == 'o') {
  1780.         s++;
  1781.         spat->spat_flags |= SPAT_KEEP;
  1782.     }
  1783.     if (*s == 'g') {
  1784.         s++;
  1785.         spat->spat_flags |= SPAT_GLOBAL;
  1786.     }
  1787.     }
  1788.     len = str->str_cur;
  1789.     e = str->str_ptr + len;
  1790.     if (delim == '\'')
  1791.     d = e;
  1792.     else
  1793.     d = str->str_ptr;
  1794.     for (; d < e; d++) {
  1795.     if (*d == '\\')
  1796.         d++;
  1797.     else if ((*d == '$' && d[1] && d[1] != '|' && d[1] != ')') ||
  1798.          (*d == '@')) {
  1799.         register ARG *arg;
  1800.  
  1801.         spat->spat_runtime = arg = op_new(1);
  1802.         arg->arg_type = O_ITEM;
  1803.         arg[1].arg_type = A_DOUBLE;
  1804.         arg[1].arg_ptr.arg_str = str_smake(str);
  1805.         d = scanident(d,bufend,buf);
  1806.         (void)stabent(buf,TRUE);        /* make sure it's created */
  1807.         for (; d < e; d++) {
  1808.         if (*d == '\\')
  1809.             d++;
  1810.         else if (*d == '$' && d[1] && d[1] != '|' && d[1] != ')') {
  1811.             d = scanident(d,bufend,buf);
  1812.             (void)stabent(buf,TRUE);
  1813.         }
  1814.         else if (*d == '@') {
  1815.             d = scanident(d,bufend,buf);
  1816.             if (strEQ(buf,"ARGV") || strEQ(buf,"ENV") ||
  1817.               strEQ(buf,"SIG") || strEQ(buf,"INC"))
  1818.             (void)stabent(buf,TRUE);
  1819.         }
  1820.         }
  1821.         goto got_pat;        /* skip compiling for now */
  1822.     }
  1823.     }
  1824.     if (spat->spat_flags & SPAT_FOLD)
  1825.     StructCopy(spat, &savespat, SPAT);
  1826.     scanconst(spat,str->str_ptr,len);
  1827.     if ((spat->spat_flags & SPAT_ALL) && (spat->spat_flags & SPAT_SCANFIRST)) {
  1828.     fbmcompile(spat->spat_short, spat->spat_flags & SPAT_FOLD);
  1829.     spat->spat_regexp = regcomp(str->str_ptr,str->str_ptr+len,
  1830.         spat->spat_flags & SPAT_FOLD);
  1831.         /* Note that this regexp can still be used if someone says
  1832.          * something like /a/ && s//b/;  so we can't delete it.
  1833.          */
  1834.     }
  1835.     else {
  1836.     if (spat->spat_flags & SPAT_FOLD)
  1837.     StructCopy(&savespat, spat, SPAT);
  1838.     if (spat->spat_short)
  1839.         fbmcompile(spat->spat_short, spat->spat_flags & SPAT_FOLD);
  1840.     spat->spat_regexp = regcomp(str->str_ptr,str->str_ptr+len,
  1841.         spat->spat_flags & SPAT_FOLD);
  1842.     hoistmust(spat);
  1843.     }
  1844.   got_pat:
  1845.     str_free(str);
  1846.     yylval.arg = make_match(O_MATCH,stab2arg(A_STAB,defstab),spat);
  1847.     return s;
  1848. }
  1849.  
  1850. char *
  1851. scansubst(start)
  1852. char *start;
  1853. {
  1854.     register char *s = start;
  1855.     register SPAT *spat;
  1856.     register char *d;
  1857.     register char *e;
  1858.     int len;
  1859.     STR *str = Str_new(93,0);
  1860.     char term = *s;
  1861.  
  1862.     if (term && (d = index("([{< )]}> )]}>",term)))
  1863.     term = d[5];
  1864.  
  1865.     Newz(802,spat,1,SPAT);
  1866.     spat->spat_next = curstash->tbl_spatroot;    /* link into spat list */
  1867.     curstash->tbl_spatroot = spat;
  1868.  
  1869.     s = str_append_till(str,s+1,bufend,term,patleave);
  1870.     if (s >= bufend) {
  1871.     str_free(str);
  1872.     yyerror("Substitution pattern not terminated");
  1873.     yylval.arg = Nullarg;
  1874.     return s;
  1875.     }
  1876.     len = str->str_cur;
  1877.     e = str->str_ptr + len;
  1878.     for (d = str->str_ptr; d < e; d++) {
  1879.     if (*d == '\\')
  1880.         d++;
  1881.     else if ((*d == '$' && d[1] && d[1] != '|' && /*(*/ d[1] != ')') ||
  1882.         *d == '@' ) {
  1883.         register ARG *arg;
  1884.  
  1885.         spat->spat_runtime = arg = op_new(1);
  1886.         arg->arg_type = O_ITEM;
  1887.         arg[1].arg_type = A_DOUBLE;
  1888.         arg[1].arg_ptr.arg_str = str_smake(str);
  1889.         d = scanident(d,e,buf);
  1890.         (void)stabent(buf,TRUE);        /* make sure it's created */
  1891.         for (; *d; d++) {
  1892.         if (*d == '$' && d[1] && d[-1] != '\\' && d[1] != '|') {
  1893.             d = scanident(d,e,buf);
  1894.             (void)stabent(buf,TRUE);
  1895.         }
  1896.         else if (*d == '@' && d[-1] != '\\') {
  1897.             d = scanident(d,e,buf);
  1898.             if (strEQ(buf,"ARGV") || strEQ(buf,"ENV") ||
  1899.               strEQ(buf,"SIG") || strEQ(buf,"INC"))
  1900.             (void)stabent(buf,TRUE);
  1901.         }
  1902.         }
  1903.         goto get_repl;        /* skip compiling for now */
  1904.     }
  1905.     }
  1906.     scanconst(spat,str->str_ptr,len);
  1907. get_repl:
  1908.     if (term != *start)
  1909.     s++;
  1910.     s = scanstr(s, SCAN_REPL);
  1911.     if (s >= bufend) {
  1912.     str_free(str);
  1913.     yyerror("Substitution replacement not terminated");
  1914.     yylval.arg = Nullarg;
  1915.     return s;
  1916.     }
  1917.     spat->spat_repl = yylval.arg;
  1918.     if ((spat->spat_repl[1].arg_type & A_MASK) == A_SINGLE)
  1919.     spat->spat_flags |= SPAT_CONST;
  1920.     else if ((spat->spat_repl[1].arg_type & A_MASK) == A_DOUBLE) {
  1921.     STR *tmpstr;
  1922.     register char *t;
  1923.  
  1924.     spat->spat_flags |= SPAT_CONST;
  1925.     tmpstr = spat->spat_repl[1].arg_ptr.arg_str;
  1926.     e = tmpstr->str_ptr + tmpstr->str_cur;
  1927.     for (t = tmpstr->str_ptr; t < e; t++) {
  1928.         if (*t == '$' && t[1] && (index("`'&+0123456789",t[1]) ||
  1929.           (t[1] == '{' /*}*/ && isDIGIT(t[2])) ))
  1930.         spat->spat_flags &= ~SPAT_CONST;
  1931.     }
  1932.     }
  1933.     while (*s == 'g' || *s == 'i' || *s == 'e' || *s == 'o') {
  1934.     int es = 0;
  1935.  
  1936.     if (*s == 'e') {
  1937.         s++;
  1938.         es++;
  1939.         if ((spat->spat_repl[1].arg_type & A_MASK) == A_DOUBLE)
  1940.         spat->spat_repl[1].arg_type = A_SINGLE;
  1941.         spat->spat_repl = make_op(
  1942.         (!es && spat->spat_repl[1].arg_type == A_SINGLE
  1943.             ? O_EVALONCE
  1944.             : O_EVAL),
  1945.         2,
  1946.         spat->spat_repl,
  1947.         Nullarg,
  1948.         Nullarg);
  1949.         spat->spat_flags &= ~SPAT_CONST;
  1950.     }
  1951.     if (*s == 'g') {
  1952.         s++;
  1953.         spat->spat_flags |= SPAT_GLOBAL;
  1954.     }
  1955.     if (*s == 'i') {
  1956.         s++;
  1957.         sawi = TRUE;
  1958.         spat->spat_flags |= SPAT_FOLD;
  1959.         if (!(spat->spat_flags & SPAT_SCANFIRST)) {
  1960.         str_free(spat->spat_short);    /* anchored opt doesn't do */
  1961.         spat->spat_short = Nullstr;    /* case insensitive match */
  1962.         spat->spat_slen = 0;
  1963.         }
  1964.     }
  1965.     if (*s == 'o') {
  1966.         s++;
  1967.         spat->spat_flags |= SPAT_KEEP;
  1968.     }
  1969.     }
  1970.     if (spat->spat_short && (spat->spat_flags & SPAT_SCANFIRST))
  1971.     fbmcompile(spat->spat_short, spat->spat_flags & SPAT_FOLD);
  1972.     if (!spat->spat_runtime) {
  1973.     spat->spat_regexp = regcomp(str->str_ptr,str->str_ptr+len,
  1974.       spat->spat_flags & SPAT_FOLD);
  1975.     hoistmust(spat);
  1976.     }
  1977.     yylval.arg = make_match(O_SUBST,stab2arg(A_STAB,defstab),spat);
  1978.     str_free(str);
  1979.     return s;
  1980. }
  1981.  
  1982. void
  1983. hoistmust(spat)
  1984. register SPAT *spat;
  1985. {
  1986.     if (!spat->spat_short && spat->spat_regexp->regstart &&
  1987.     (!spat->spat_regexp->regmust || spat->spat_regexp->reganch & ROPT_ANCH)
  1988.        ) {
  1989.     if (!(spat->spat_regexp->reganch & ROPT_ANCH))
  1990.         spat->spat_flags |= SPAT_SCANFIRST;
  1991.     else if (spat->spat_flags & SPAT_FOLD)
  1992.         return;
  1993.     spat->spat_short = str_smake(spat->spat_regexp->regstart);
  1994.     }
  1995.     else if (spat->spat_regexp->regmust) {/* is there a better short-circuit? */
  1996.     if (spat->spat_short &&
  1997.       str_eq(spat->spat_short,spat->spat_regexp->regmust))
  1998.     {
  1999.         if (spat->spat_flags & SPAT_SCANFIRST) {
  2000.         str_free(spat->spat_short);
  2001.         spat->spat_short = Nullstr;
  2002.         }
  2003.         else {
  2004.         str_free(spat->spat_regexp->regmust);
  2005.         spat->spat_regexp->regmust = Nullstr;
  2006.         return;
  2007.         }
  2008.     }
  2009.     if (!spat->spat_short ||    /* promote the better string */
  2010.       ((spat->spat_flags & SPAT_SCANFIRST) &&
  2011.        (spat->spat_short->str_cur < spat->spat_regexp->regmust->str_cur) )){
  2012.         str_free(spat->spat_short);        /* ok if null */
  2013.         spat->spat_short = spat->spat_regexp->regmust;
  2014.         spat->spat_regexp->regmust = Nullstr;
  2015.         spat->spat_flags |= SPAT_SCANFIRST;
  2016.     }
  2017.     }
  2018. }
  2019.  
  2020. char *
  2021. scantrans(start)
  2022. char *start;
  2023. {
  2024.     register char *s = start;
  2025.     ARG *arg =
  2026.     l(make_op(O_TRANS,2,stab2arg(A_STAB,defstab),Nullarg,Nullarg));
  2027.     STR *tstr;
  2028.     STR *rstr;
  2029.     register char *t;
  2030.     register char *r;
  2031.     register short *tbl;
  2032.     register int i;
  2033.     register int j;
  2034.     int tlen, rlen;
  2035.     int squash;
  2036.     int delete;
  2037.     int complement;
  2038.  
  2039.     New(803,tbl,256,short);
  2040.     arg[2].arg_type = A_NULL;
  2041.     arg[2].arg_ptr.arg_cval = (char*) tbl;
  2042.  
  2043.     s = scanstr(s, SCAN_TR);
  2044.     if (s >= bufend) {
  2045.     yyerror("Translation pattern not terminated");
  2046.     yylval.arg = Nullarg;
  2047.     return s;
  2048.     }
  2049.     tstr = yylval.arg[1].arg_ptr.arg_str; 
  2050.     yylval.arg[1].arg_ptr.arg_str = Nullstr; 
  2051.     arg_free(yylval.arg);
  2052.     t = tstr->str_ptr;
  2053.     tlen = tstr->str_cur;
  2054.  
  2055.     if (s[-1] == *start)
  2056.     s--;
  2057.  
  2058.     s = scanstr(s, SCAN_TR|SCAN_REPL);
  2059.     if (s >= bufend) {
  2060.     yyerror("Translation replacement not terminated");
  2061.     yylval.arg = Nullarg;
  2062.     return s;
  2063.     }
  2064.     rstr = yylval.arg[1].arg_ptr.arg_str; 
  2065.     yylval.arg[1].arg_ptr.arg_str = Nullstr; 
  2066.     arg_free(yylval.arg);
  2067.     r = rstr->str_ptr;
  2068.     rlen = rstr->str_cur;
  2069.  
  2070.     complement = delete = squash = 0;
  2071.     while (*s == 'c' || *s == 'd' || *s == 's') {
  2072.     if (*s == 'c')
  2073.         complement = 1;
  2074.     else if (*s == 'd')
  2075.         delete = 2;
  2076.     else
  2077.         squash = 1;
  2078.     s++;
  2079.     }
  2080.     arg[2].arg_len = delete|squash;
  2081.     yylval.arg = arg;
  2082.     if (complement) {
  2083.     Zero(tbl, 256, short);
  2084.     for (i = 0; i < tlen; i++)
  2085.         tbl[t[i] & 0377] = -1;
  2086.     for (i = 0, j = 0; i < 256; i++) {
  2087.         if (!tbl[i]) {
  2088.         if (j >= rlen) {
  2089.             if (delete)
  2090.             tbl[i] = -2;
  2091.             else if (rlen)
  2092.             tbl[i] = r[j-1] & 0377;
  2093.             else
  2094.             tbl[i] = i;
  2095.         }
  2096.         else
  2097.             tbl[i] = r[j++] & 0377;
  2098.         }
  2099.     }
  2100.     }
  2101.     else {
  2102.     if (!rlen && !delete) {
  2103.         r = t; rlen = tlen;
  2104.     }
  2105.     for (i = 0; i < 256; i++)
  2106.         tbl[i] = -1;
  2107.     for (i = 0, j = 0; i < tlen; i++,j++) {
  2108.         if (j >= rlen) {
  2109.         if (delete) {
  2110.             if (tbl[t[i] & 0377] == -1)
  2111.             tbl[t[i] & 0377] = -2;
  2112.             continue;
  2113.         }
  2114.         --j;
  2115.         }
  2116.         if (tbl[t[i] & 0377] == -1)
  2117.         tbl[t[i] & 0377] = r[j] & 0377;
  2118.     }
  2119.     }
  2120.     str_free(tstr);
  2121.     str_free(rstr);
  2122.     return s;
  2123. }
  2124.  
  2125. char *
  2126. scanstr(start, in_what)
  2127. char *start;
  2128. int in_what;
  2129. {
  2130.     register char *s = start;
  2131.     register char term;
  2132.     register char *d;
  2133.     register ARG *arg;
  2134.     register char *send;
  2135.     register bool makesingle = FALSE;
  2136.     register STAB *stab;
  2137.     bool alwaysdollar = FALSE;
  2138.     bool hereis = FALSE;
  2139.     STR *herewas;
  2140.     STR *str;
  2141.     /* which backslash sequences to keep */
  2142.     char *leave = (in_what & SCAN_TR)
  2143.     ? "\\$@nrtfbeacx0123456789-"
  2144.     : "\\$@nrtfbeacx0123456789[{]}lLuUE";
  2145.     int len;
  2146.  
  2147.     arg = op_new(1);
  2148.     yylval.arg = arg;
  2149.     arg->arg_type = O_ITEM;
  2150.  
  2151.     switch (*s) {
  2152.     default:            /* a substitution replacement */
  2153.     arg[1].arg_type = A_DOUBLE;
  2154.     makesingle = TRUE;    /* maybe disable runtime scanning */
  2155.     term = *s;
  2156.     if (term == '\'')
  2157.         leave = Nullch;
  2158.     goto snarf_it;
  2159.     case '0':
  2160.     {
  2161.         unsigned long i;
  2162.         int shift;
  2163.  
  2164.         arg[1].arg_type = A_SINGLE;
  2165.         if (s[1] == 'x') {
  2166.         shift = 4;
  2167.         s += 2;
  2168.         }
  2169.         else if (s[1] == '.')
  2170.         goto decimal;
  2171.         else
  2172.         shift = 3;
  2173.         i = 0;
  2174.         for (;;) {
  2175.         switch (*s) {
  2176.         default:
  2177.             goto out;
  2178.         case '_':
  2179.             s++;
  2180.             break;
  2181.         case '8': case '9':
  2182.             if (shift != 4)
  2183.             yyerror("Illegal octal digit");
  2184.             /* FALL THROUGH */
  2185.         case '0': case '1': case '2': case '3': case '4':
  2186.         case '5': case '6': case '7':
  2187.             i <<= shift;
  2188.             i += *s++ & 15;
  2189.             break;
  2190.         case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
  2191.         case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
  2192.             if (shift != 4)
  2193.             goto out;
  2194.             i <<= 4;
  2195.             i += (*s++ & 7) + 9;
  2196.             break;
  2197.         }
  2198.         }
  2199.       out:
  2200.         str = Str_new(92,0);
  2201.         str_numset(str,(double)i);
  2202.         if (str->str_ptr) {
  2203.         Safefree(str->str_ptr);
  2204.         str->str_ptr = Nullch;
  2205.         str->str_len = str->str_cur = 0;
  2206.         }
  2207.         arg[1].arg_ptr.arg_str = str;
  2208.     }
  2209.     break;
  2210.     case '1': case '2': case '3': case '4': case '5':
  2211.     case '6': case '7': case '8': case '9': case '.':
  2212.       decimal:
  2213.     arg[1].arg_type = A_SINGLE;
  2214.     d = tokenbuf;
  2215.     while (isDIGIT(*s) || *s == '_') {
  2216.         if (*s == '_')
  2217.         s++;
  2218.         else
  2219.         *d++ = *s++;
  2220.     }
  2221.     if (*s == '.' && s[1] != '.') {
  2222.         *d++ = *s++;
  2223.         while (isDIGIT(*s) || *s == '_') {
  2224.         if (*s == '_')
  2225.             s++;
  2226.         else
  2227.             *d++ = *s++;
  2228.         }
  2229.     }
  2230.     if (*s && index("eE",*s) && index("+-0123456789",s[1])) {
  2231.         *d++ = *s++;
  2232.         if (*s == '+' || *s == '-')
  2233.         *d++ = *s++;
  2234.         while (isDIGIT(*s))
  2235.         *d++ = *s++;
  2236.     }
  2237.     *d = '\0';
  2238.     str = Str_new(92,0);
  2239.     str_numset(str,atof(tokenbuf));
  2240.     if (str->str_ptr) {
  2241.         Safefree(str->str_ptr);
  2242.         str->str_ptr = Nullch;
  2243.         str->str_len = str->str_cur = 0;
  2244.     }
  2245.     arg[1].arg_ptr.arg_str = str;
  2246.     break;
  2247.     case '<':
  2248.     if (in_what & (SCAN_REPL|SCAN_TR))
  2249.         goto do_double;
  2250.     if (*++s == '<') {
  2251.         hereis = TRUE;
  2252.         d = tokenbuf;
  2253.         if (!rsfp)
  2254.         *d++ = '\n';
  2255.         if (*++s && index("`'\"",*s)) {
  2256.         term = *s++;
  2257.         s = cpytill(d,s,bufend,term,&len);
  2258.         if (s < bufend)
  2259.             s++;
  2260.         d += len;
  2261.         }
  2262.         else {
  2263.         if (*s == '\\')
  2264.             s++, term = '\'';
  2265.         else
  2266.             term = '"';
  2267.         while (isALNUM(*s))
  2268.             *d++ = *s++;
  2269.         }                /* assuming tokenbuf won't clobber */
  2270.         *d++ = '\n';
  2271.         *d = '\0';
  2272.         len = d - tokenbuf;
  2273.         d = "\n";
  2274.         if (rsfp || !(d=ninstr(s,bufend,d,d+1)))
  2275.         herewas = str_make(s,bufend-s);
  2276.         else
  2277.         s--, herewas = str_make(s,d-s);
  2278.         s += herewas->str_cur;
  2279.         if (term == '\'')
  2280.         goto do_single;
  2281.         if (term == '`')
  2282.         goto do_back;
  2283.         goto do_double;
  2284.     }
  2285.     d = tokenbuf;
  2286.     s = cpytill(d,s,bufend,'>',&len);
  2287.     if (s < bufend)
  2288.         s++;
  2289.     else
  2290.         fatal("Unterminated <> operator");
  2291.  
  2292.     if (*d == '$') d++;
  2293.     while (*d && (isALNUM(*d) || *d == '\''))
  2294.         d++;
  2295.     if (d - tokenbuf != len) {
  2296.         s = start;
  2297.         term = *s;
  2298.         arg[1].arg_type = A_GLOB;
  2299.         set_csh();
  2300.         alwaysdollar = TRUE;    /* treat $) and $| as variables */
  2301.         goto snarf_it;
  2302.     }
  2303.     else {
  2304.         d = tokenbuf;
  2305.         if (!len)
  2306.         (void)strcpy(d,"ARGV");
  2307.         if (*d == '$') {
  2308.         arg[1].arg_type = A_INDREAD;
  2309.         arg[1].arg_ptr.arg_stab = stabent(d+1,TRUE);
  2310.         }
  2311.         else {
  2312.         arg[1].arg_type = A_READ;
  2313.         arg[1].arg_ptr.arg_stab = stabent(d,TRUE);
  2314.         if (!stab_io(arg[1].arg_ptr.arg_stab))
  2315.             stab_io(arg[1].arg_ptr.arg_stab) = stio_new();
  2316.         if (strEQ(d,"ARGV")) {
  2317.             (void)aadd(arg[1].arg_ptr.arg_stab);
  2318.             stab_io(arg[1].arg_ptr.arg_stab)->flags |=
  2319.               IOF_ARGV|IOF_START;
  2320.         }
  2321.         }
  2322.     }
  2323.     break;
  2324.  
  2325.     case 'q':
  2326.     s++;
  2327.     if (*s == 'q') {
  2328.         s++;
  2329.         goto do_double;
  2330.     }
  2331.     if (*s == 'x') {
  2332.         s++;
  2333.         goto do_back;
  2334.     }
  2335.     /* FALL THROUGH */
  2336.     case '\'':
  2337.       do_single:
  2338.     term = *s;
  2339.     arg[1].arg_type = A_SINGLE;
  2340.     leave = Nullch;
  2341.     goto snarf_it;
  2342.  
  2343.     case '"': 
  2344.       do_double:
  2345.     term = *s;
  2346.     arg[1].arg_type = A_DOUBLE;
  2347.     makesingle = TRUE;    /* maybe disable runtime scanning */
  2348.     alwaysdollar = TRUE;    /* treat $) and $| as variables */
  2349.     goto snarf_it;
  2350.     case '`':
  2351.       do_back:
  2352.     term = *s;
  2353.     arg[1].arg_type = A_BACKTICK;
  2354.     set_csh();
  2355.     alwaysdollar = TRUE;    /* treat $) and $| as variables */
  2356.       snarf_it:
  2357.     {
  2358.         STR *tmpstr;
  2359.         STR *tmpstr2 = Nullstr;
  2360.         char *tmps;
  2361.         char *start;
  2362.         bool dorange = FALSE;
  2363.  
  2364.         CLINE;
  2365.         multi_start = curcmd->c_line;
  2366.         if (hereis)
  2367.         multi_open = multi_close = '<';
  2368.         else {
  2369.         multi_open = term;
  2370.         if (term && (tmps = index("([{< )]}> )]}>",term)))
  2371.             term = tmps[5];
  2372.         multi_close = term;
  2373.         }
  2374.         tmpstr = Str_new(87,80);
  2375.         if (hereis) {
  2376.         term = *tokenbuf;
  2377.         if (!rsfp) {
  2378.             d = s;
  2379.             while (s < bufend &&
  2380.               (*s != term || bcmp(s,tokenbuf,len) != 0) ) {
  2381.             if (*s++ == '\n')
  2382.                 curcmd->c_line++;
  2383.             }
  2384.             if (s >= bufend) {
  2385.             curcmd->c_line = multi_start;
  2386.             fatal("EOF in string");
  2387.             }
  2388.             str_nset(tmpstr,d+1,s-d);
  2389.             s += len - 1;
  2390.             str_ncat(herewas,s,bufend-s);
  2391.             str_replace(linestr,herewas);
  2392.             oldoldbufptr = oldbufptr = bufptr = s = str_get(linestr);
  2393.             bufend = linestr->str_ptr + linestr->str_cur;
  2394.             hereis = FALSE;
  2395.         }
  2396.         else
  2397.             str_nset(tmpstr,"",0);   /* avoid "uninitialized" warning */
  2398.         }
  2399.         else
  2400.         s = str_append_till(tmpstr,s+1,bufend,term,leave);
  2401.         while (s >= bufend) {    /* multiple line string? */
  2402.         if (!rsfp ||
  2403.          !(oldoldbufptr = oldbufptr = s = str_gets(linestr, rsfp, 0))) {
  2404.             curcmd->c_line = multi_start;
  2405.             fatal("EOF in string");
  2406.         }
  2407.         curcmd->c_line++;
  2408.         if (perldb) {
  2409.             STR *str = Str_new(88,0);
  2410.  
  2411.             str_sset(str,linestr);
  2412.             astore(stab_xarray(curcmd->c_filestab),
  2413.               (int)curcmd->c_line,str);
  2414.         }
  2415.         bufend = linestr->str_ptr + linestr->str_cur;
  2416.         if (hereis) {
  2417.             if (*s == term && bcmp(s,tokenbuf,len) == 0) {
  2418.             s = bufend - 1;
  2419.             *s = ' ';
  2420.             str_scat(linestr,herewas);
  2421.             bufend = linestr->str_ptr + linestr->str_cur;
  2422.             }
  2423.             else {
  2424.             s = bufend;
  2425.             str_scat(tmpstr,linestr);
  2426.             }
  2427.         }
  2428.         else
  2429.             s = str_append_till(tmpstr,s,bufend,term,leave);
  2430.         }
  2431.         multi_end = curcmd->c_line;
  2432.         s++;
  2433.         if (tmpstr->str_cur + 5 < tmpstr->str_len) {
  2434.         tmpstr->str_len = tmpstr->str_cur + 1;
  2435.         Renew(tmpstr->str_ptr, tmpstr->str_len, char);
  2436.         }
  2437.         if (arg[1].arg_type == A_SINGLE) {
  2438.         arg[1].arg_ptr.arg_str = tmpstr;
  2439.         break;
  2440.         }
  2441.         tmps = s;
  2442.         s = tmpstr->str_ptr;
  2443.         send = s + tmpstr->str_cur;
  2444.         while (s < send) {        /* see if we can make SINGLE */
  2445.         if (*s == '\\' && s[1] && isDIGIT(s[1]) && !isDIGIT(s[2]) &&
  2446.           !alwaysdollar && s[1] != '0')
  2447.             *s = '$';        /* grandfather \digit in subst */
  2448.         if ((*s == '$' || *s == '@') && s+1 < send &&
  2449.           (alwaysdollar || (s[1] != ')' && s[1] != '|'))) {
  2450.             makesingle = FALSE;    /* force interpretation */
  2451.         }
  2452.         else if (*s == '\\' && s+1 < send) {
  2453.             if (index("lLuUE",s[1]))
  2454.             makesingle = FALSE;
  2455.             s++;
  2456.         }
  2457.         s++;
  2458.         }
  2459.         s = d = start = tmpstr->str_ptr;    /* assuming shrinkage only */
  2460.         while (s < send || dorange) {
  2461.         if (in_what & SCAN_TR) {
  2462.             if (dorange) {
  2463.             int i;
  2464.             int max;
  2465.             if (!tmpstr2) {    /* oops, have to grow */
  2466.                 tmpstr2 = str_smake(tmpstr);
  2467.                 s = tmpstr2->str_ptr + (s - tmpstr->str_ptr);
  2468.                 send = tmpstr2->str_ptr + (send - tmpstr->str_ptr);
  2469.             }
  2470.             i = d - tmpstr->str_ptr;
  2471.             STR_GROW(tmpstr, tmpstr->str_len + 256);
  2472.             d = tmpstr->str_ptr + i;
  2473.             d -= 2;
  2474.             max = d[1] & 0377;
  2475.             for (i = (*d & 0377); i <= max; i++)
  2476.                 *d++ = i;
  2477.             start = s;
  2478.             dorange = FALSE;
  2479.             continue;
  2480.             }
  2481.             else if (*s == '-' && s+1 < send  && s != start) {
  2482.             dorange = TRUE;
  2483.             s++;
  2484.             }
  2485.         }
  2486.         else {
  2487.             if ((*s == '$' && s+1 < send &&
  2488.             (alwaysdollar || /*(*/(s[1] != ')' && s[1] != '|')) ) ||
  2489.             (*s == '@' && s+1 < send) ) {
  2490.             if (s[1] == '#' && (isALPHA(s[2]) || s[2] == '_'))
  2491.                 *d++ = *s++;
  2492.             len = scanident(s,send,tokenbuf) - s;
  2493.             if (*s == '$' || strEQ(tokenbuf,"ARGV")
  2494.               || strEQ(tokenbuf,"ENV")
  2495.               || strEQ(tokenbuf,"SIG")
  2496.               || strEQ(tokenbuf,"INC") )
  2497.                 (void)stabent(tokenbuf,TRUE); /* add symbol */
  2498.             while (len--)
  2499.                 *d++ = *s++;
  2500.             continue;
  2501.             }
  2502.         }
  2503.         if (*s == '\\' && s+1 < send) {
  2504.             s++;
  2505.             switch (*s) {
  2506.             case '-':
  2507.             if (in_what & SCAN_TR) {
  2508.                 *d++ = *s++;
  2509.                 continue;
  2510.             }
  2511.             /* FALL THROUGH */
  2512.             default:
  2513.             if (!makesingle && (!leave || (*s && index(leave,*s))))
  2514.                 *d++ = '\\';
  2515.             *d++ = *s++;
  2516.             continue;
  2517.             case '0': case '1': case '2': case '3':
  2518.             case '4': case '5': case '6': case '7':
  2519.             *d++ = scanoct(s, 3, &len);
  2520.             s += len;
  2521.             continue;
  2522.             case 'x':
  2523.             *d++ = scanhex(++s, 2, &len);
  2524.             s += len;
  2525.             continue;
  2526.             case 'c':
  2527.             s++;
  2528.             *d = *s++;
  2529.             if (isLOWER(*d))
  2530.                 *d = toupper(*d);
  2531.             *d++ ^= 64;
  2532.             continue;
  2533.             case 'b':
  2534.             *d++ = '\b';
  2535.             break;
  2536.             case 'n':
  2537.             *d++ = '\n';
  2538.             break;
  2539.             case 'r':
  2540.             *d++ = '\r';
  2541.             break;
  2542.             case 'f':
  2543.             *d++ = '\f';
  2544.             break;
  2545.             case 't':
  2546.             *d++ = '\t';
  2547.             break;
  2548.             case 'e':
  2549.             *d++ = '\033';
  2550.             break;
  2551.             case 'a':
  2552.             *d++ = '\007';
  2553.             break;
  2554.             }
  2555.             s++;
  2556.             continue;
  2557.         }
  2558.         *d++ = *s++;
  2559.         }
  2560.         *d = '\0';
  2561.  
  2562.         if (arg[1].arg_type == A_DOUBLE && makesingle)
  2563.         arg[1].arg_type = A_SINGLE;    /* now we can optimize on it */
  2564.  
  2565.         tmpstr->str_cur = d - tmpstr->str_ptr;
  2566.         if (arg[1].arg_type == A_GLOB) {
  2567.         arg[1].arg_ptr.arg_stab = stab = genstab();
  2568.         stab_io(stab) = stio_new();
  2569.         str_sset(stab_val(stab), tmpstr);
  2570.         }
  2571.         else
  2572.         arg[1].arg_ptr.arg_str = tmpstr;
  2573.         s = tmps;
  2574.         if (tmpstr2)
  2575.         str_free(tmpstr2);
  2576.         break;
  2577.     }
  2578.     }
  2579.     if (hereis)
  2580.     str_free(herewas);
  2581.     return s;
  2582. }
  2583.  
  2584. FCMD *
  2585. load_format()
  2586. {
  2587.     FCMD froot;
  2588.     FCMD *flinebeg;
  2589.     char *eol;
  2590.     register FCMD *fprev = &froot;
  2591.     register FCMD *fcmd;
  2592.     register char *s;
  2593.     register char *t;
  2594.     register STR *str;
  2595.     bool noblank;
  2596.     bool repeater;
  2597.  
  2598.     Zero(&froot, 1, FCMD);
  2599.     s = bufptr;
  2600.     while (s < bufend || (rsfp && (s = str_gets(linestr,rsfp, 0)) != Nullch)) {
  2601.     curcmd->c_line++;
  2602.     if (in_eval && !rsfp) {
  2603.         eol = index(s,'\n');
  2604.         if (!eol++)
  2605.         eol = bufend;
  2606.     }
  2607.     else
  2608.         eol = bufend = linestr->str_ptr + linestr->str_cur;
  2609.     if (perldb) {
  2610.         STR *tmpstr = Str_new(89,0);
  2611.  
  2612.         str_nset(tmpstr, s, eol-s);
  2613.         astore(stab_xarray(curcmd->c_filestab), (int)curcmd->c_line,tmpstr);
  2614.     }
  2615.     if (*s == '.') {
  2616.         /*SUPPRESS 530*/
  2617.         for (t = s+1; *t == ' ' || *t == '\t'; t++) ;
  2618.         if (*t == '\n') {
  2619.         bufptr = s;
  2620.         return froot.f_next;
  2621.         }
  2622.     }
  2623.     if (*s == '#') {
  2624.         s = eol;
  2625.         continue;
  2626.     }
  2627.     flinebeg = Nullfcmd;
  2628.     noblank = FALSE;
  2629.     repeater = FALSE;
  2630.     while (s < eol) {
  2631.         Newz(804,fcmd,1,FCMD);
  2632.         fprev->f_next = fcmd;
  2633.         fprev = fcmd;
  2634.         for (t=s; t < eol && *t != '@' && *t != '^'; t++) {
  2635.         if (*t == '~') {
  2636.             noblank = TRUE;
  2637.             *t = ' ';
  2638.             if (t[1] == '~') {
  2639.             repeater = TRUE;
  2640.             t[1] = ' ';
  2641.             }
  2642.         }
  2643.         }
  2644.         fcmd->f_pre = nsavestr(s, t-s);
  2645.         fcmd->f_presize = t-s;
  2646.         s = t;
  2647.         if (s >= eol) {
  2648.         if (noblank)
  2649.             fcmd->f_flags |= FC_NOBLANK;
  2650.         if (repeater)
  2651.             fcmd->f_flags |= FC_REPEAT;
  2652.         break;
  2653.         }
  2654.         if (!flinebeg)
  2655.         flinebeg = fcmd;        /* start values here */
  2656.         if (*s++ == '^')
  2657.         fcmd->f_flags |= FC_CHOP;    /* for doing text filling */
  2658.         switch (*s) {
  2659.         case '*':
  2660.         fcmd->f_type = F_LINES;
  2661.         *s = '\0';
  2662.         break;
  2663.         case '<':
  2664.         fcmd->f_type = F_LEFT;
  2665.         while (*s == '<')
  2666.             s++;
  2667.         break;
  2668.         case '>':
  2669.         fcmd->f_type = F_RIGHT;
  2670.         while (*s == '>')
  2671.             s++;
  2672.         break;
  2673.         case '|':
  2674.         fcmd->f_type = F_CENTER;
  2675.         while (*s == '|')
  2676.             s++;
  2677.         break;
  2678.         case '#':
  2679.         case '.':
  2680.         /* Catch the special case @... and handle it as a string
  2681.            field. */
  2682.         if (*s == '.' && s[1] == '.') {
  2683.             goto default_format;
  2684.         }
  2685.         fcmd->f_type = F_DECIMAL;
  2686.         {
  2687.             char *p;
  2688.  
  2689.             /* Read a format in the form @####.####, where either group
  2690.                of ### may be empty, or the final .### may be missing. */
  2691.             while (*s == '#')
  2692.             s++;
  2693.             if (*s == '.') {
  2694.             s++;
  2695.             p = s;
  2696.             while (*s == '#')
  2697.                 s++;
  2698.             fcmd->f_decimals = s-p;
  2699.             fcmd->f_flags |= FC_DP;
  2700.             } else {
  2701.             fcmd->f_decimals = 0;
  2702.             }
  2703.         }
  2704.         break;
  2705.         default:
  2706.         default_format:
  2707.         fcmd->f_type = F_LEFT;
  2708.         break;
  2709.         }
  2710.         if (fcmd->f_flags & FC_CHOP && *s == '.') {
  2711.         fcmd->f_flags |= FC_MORE;
  2712.         while (*s == '.')
  2713.             s++;
  2714.         }
  2715.         fcmd->f_size = s-t;
  2716.     }
  2717.     if (flinebeg) {
  2718.       again:
  2719.         if (s >= bufend &&
  2720.           (!rsfp || (s = str_gets(linestr, rsfp, 0)) == Nullch) )
  2721.         goto badform;
  2722.         curcmd->c_line++;
  2723.         if (in_eval && !rsfp) {
  2724.         eol = index(s,'\n');
  2725.         if (!eol++)
  2726.             eol = bufend;
  2727.         }
  2728.         else
  2729.         eol = bufend = linestr->str_ptr + linestr->str_cur;
  2730.         if (perldb) {
  2731.         STR *tmpstr = Str_new(90,0);
  2732.  
  2733.         str_nset(tmpstr, s, eol-s);
  2734.         astore(stab_xarray(curcmd->c_filestab),
  2735.             (int)curcmd->c_line,tmpstr);
  2736.         }
  2737.         if (strnEQ(s,".\n",2)) {
  2738.         bufptr = s;
  2739.         yyerror("Missing values line");
  2740.         return froot.f_next;
  2741.         }
  2742.         if (*s == '#') {
  2743.         s = eol;
  2744.         goto again;
  2745.         }
  2746.         str = flinebeg->f_unparsed = Str_new(91,eol - s);
  2747.         str->str_u.str_hash = curstash;
  2748.         str_nset(str,"(",1);
  2749.         flinebeg->f_line = curcmd->c_line;
  2750.         eol[-1] = '\0';
  2751.         if (!flinebeg->f_next->f_type || index(s, ',')) {
  2752.         eol[-1] = '\n';
  2753.         str_ncat(str, s, eol - s - 1);
  2754.         str_ncat(str,",$$);",5);
  2755.         s = eol;
  2756.         }
  2757.         else {
  2758.         eol[-1] = '\n';
  2759.         while (s < eol && isSPACE(*s))
  2760.             s++;
  2761.         t = s;
  2762.         while (s < eol) {
  2763.             switch (*s) {
  2764.             case ' ': case '\t': case '\n': case ';':
  2765.             str_ncat(str, t, s - t);
  2766.             str_ncat(str, "," ,1);
  2767.             while (s < eol && (isSPACE(*s) || *s == ';'))
  2768.                 s++;
  2769.             t = s;
  2770.             break;
  2771.             case '$':
  2772.             str_ncat(str, t, s - t);
  2773.             t = s;
  2774.             s = scanident(s,eol,tokenbuf);
  2775.             str_ncat(str, t, s - t);
  2776.             t = s;
  2777.             if (s < eol && *s && index("$'\"",*s))
  2778.                 str_ncat(str, ",", 1);
  2779.             break;
  2780.             case '"': case '\'':
  2781.             str_ncat(str, t, s - t);
  2782.             t = s;
  2783.             s++;
  2784.             while (s < eol && (*s != *t || s[-1] == '\\'))
  2785.                 s++;
  2786.             if (s < eol)
  2787.                 s++;
  2788.             str_ncat(str, t, s - t);
  2789.             t = s;
  2790.             if (s < eol && *s && index("$'\"",*s))
  2791.                 str_ncat(str, ",", 1);
  2792.             break;
  2793.             default:
  2794.             yyerror("Please use commas to separate fields");
  2795.             }
  2796.         }
  2797.         str_ncat(str,"$$);",4);
  2798.         }
  2799.     }
  2800.     }
  2801.   badform:
  2802.     bufptr = str_get(linestr);
  2803.     yyerror("Format not terminated");
  2804.     return froot.f_next;
  2805. }
  2806.  
  2807. static void
  2808. set_csh()
  2809. {
  2810. #ifdef CSH
  2811.     if (!cshlen)
  2812.     cshlen = strlen(cshname);
  2813. #endif
  2814. }
  2815.  
  2816. #ifdef macintosh
  2817. void reinit_toke()
  2818. {
  2819.     reparse     = NULL;
  2820.     last_uni    = NULL;
  2821.     in_format     = FALSE;
  2822.     firstline     = TRUE;
  2823. }
  2824. #endif
  2825.